<?php
/**
* Definiert Konstanten fuer Umgang mit dem UserAgent.
*
* <i>void defAgentConstants([mixed mobile_ids [, bool landscape_mode]])</i>
*
* Ermittelt Browser-Typ (mobile / non-mobile) sowie Breite, Hoehe und Farbtiefe
* des Browser-Displays durch Auswertung entsprechender Daten aus
* - spezifischen Request-Headern oder
* - User-Agent-String (<b>ggf. $_SERVER['HTTP_USER_AGENT'] vorher initialisieren!</b>) oder
* - spezifischem URL-Parameter
*
* @version 080516
* @since 060505
* @author Cybaer <cybaer@binon.net>
* @copyright Copyright (c) 2006-08 Cybaer
* @license CC <http://creativecommons.org/licenses/by-nc-sa/2.5/>
*
* @category SYSTEM_DEFINITION
* @access public
*
* @uses ifsetor()
* @uses instr()
* @uses from()
*
* @param mixed $mMobileIDs Ein Array oder (Pipe-separierter) String mit (Ausschnitten aus) UserAgent-Kennungen mobiler Clients
* @param bool $bLandscapeMode Wenn Abmessungen fuer Landscape-Modus (iPhone) ermittelt werden sollen TRUE, Portrait-Modus FALSE (Default)
* Example: <code><?php
* // Windows Mobile agent info by request header, i.e. 240x320 with 8 bit monochrome:
* // $_SERVER['HTTP_UA_PIXELS'] is "240x320";
* // $_SERVER['HTTP_UA_COLOR'] is "mono8";
* // or OpenWave info by request header, i.e. 240x320 with 16 bit color:
* // $_SERVER['HTTP_X_UP_DEVCAP_SCREENPIXELS'] is "240,320";
* // $_SERVER['HTTP_X_UP_DEVCAP_SCREENDEPTH'] is "16";
* // $_SERVER['HTTP_X_UP_DEVCAP_ISCOLOR'] is "1";
* // or other agent info by request header, i.e. 240x320 with 18 bit color:
* // $_SERVER['HTTP_X_JPHONE_DISPLAY'] is "240*320";
* // $_SERVER['HTTP_X_JPHONE_COLOR'] is "C262144";
* // or
* // $_SERVER['HTTP_X_OS_PREFS'] is "fw:240; fh:320; cd:18c; pl:3; pj:1; pa:1;pi:1;ps:0;"
* // or agent info by User-Agent: header, i.e. 240x320 with 16 bit display:
* // $_SERVER['HTTP_USER_AGENT'] contains "240x320x16" or "16;240x320"
* // or agent info by URL parameter, i.e. 1 bit // 4 bit monochrome // 16 bit color:
* // myscript.php?AGENT_DISPLAY=240x320x1 // 240x230x4mono // 240x230x16color
* echo ((MOBILE_AGENT)?'Mobile ':'').AGENT_WIDTH.'x'.AGENT_HEIGHT.' '.((AGENT_MONO)?'monochrome':'color').' display with '.((AGENT_DEPTH<32)?(((!AGENT_DEPTH)?'unknown':pow(2,AGENT_DEPTH)).' colors'):'truecolor').'.<br>';
* echo 'Client environment: '.ifsetor(AGENT_WIDTH,'?').'x'.ifsetor(AGENT_HEIGHT,'?').' pixel ('.((MOBILE_AGENT===FALSE)?'non-':'').'mobile'.((MOBILE_AGENT===NULL)?'?':'').' device</span> with <span title="Constant: AGENT_DEPTH">'.ifsetor(AGENT_DEPTH,'?').' bit</span> <span title="Constant: AGENT_MONO">'.((AGENT_MONO)?'monochrome':'color').((AGENT_MONO===NULL)?'?':'').' display</span>)<br>';
* ?></code>
*/
function defAgentConstants($mMobileIDs=NULL,$bLandscapeMode=TRUE) {
// UA-Kennstrings (s. http://www.zytrax.com/tech/web/mobile_ids.html ) - Nintendo Wii wird als Mobilgeraet gewertet
if(empty($mMobileIDs)) { $mMobileIDs='Windows CE|PIE|Pocket|Mobile|Portable|portal|Smartphone|SDA|PDA|Handheld|Symbian|EPOC|WAP|Palm|Plucker|Blazer|CHTML|CLDC|RegKing|ReqwirelessWeb|Netfront|UP.Browser|UP.Link|BlackBerry|Minimo|Opera Mini|Nitro|PS2|Wii|OPWV|Xiino|SEC-SGH|Nokia|Vodafone|J-PHONE|DoCoMo|Avantgo'; }
// Aufloesungsgrenze fuer Definition "Mobilgeraet" (PDA) festlegen (sofern nicht bereits vorher geschehen)
@define('MOBILE_MAX_WIDTH',800);
@define('MOBILE_MAX_HEIGHT',600);
// Maximale Bitanzahl festlegen, bis zu der das Display als "monochrome" eingestuft werden soll
@define('MONO_MAX_DEPTH',4);
// Wenn UserAgent seine Aufloesung nicht in HTTP_UA_PIXELS sendet ...
if(empty($_SERVER['HTTP_UA_PIXELS'])) {
// ... Alternativen versuchen (und Ergebnis einheitlich nach HTTP_UA_PIXELS):
if(!empty($_SERVER['HTTP_X_OS_PREFS'])) {
if(instr($_SERVER['HTTP_X_OS_PREFS'],'fw:|fh:',0,TRUE,TRUE,TRUE)) {
$_SERVER['HTTP_UA_PIXELS']=intval(substr($_SERVER['HTTP_X_OS_PREFS'],strpos($_SERVER['HTTP_X_OS_PREFS'],'fw:')+3)).'x'.intval(substr($_SERVER['HTTP_X_OS_PREFS'],strpos($_SERVER['HTTP_X_OS_PREFS'],'fh:')+3));
}
$_LOCAL_['UA_DEPTH_POS']=strpos($_SERVER['HTTP_X_OS_PREFS'],'cd:');
if($_LOCAL_['UA_DEPTH_POS']!==FALSE) {
$_LOCAL_['UA_DEPTH']=substr($_SERVER['HTTP_X_OS_PREFS'],$_LOCAL_['UA_DEPTH_POS']+3,strpos($_SERVER['HTTP_X_OS_PREFS'],';',$_LOCAL_['UA_DEPTH_POS'])-$_LOCAL_['UA_DEPTH_POS']-3);
$_SERVER['HTTP_UA_COLOR']=((substr($_LOCAL_['UA_DEPTH'],-1)=='c')?'color':'mono').intval(substr($_SERVER['HTTP_X_OS_PREFS'],strpos($_SERVER['HTTP_X_OS_PREFS'],'cd:')+3));
}
} else if(!empty($_SERVER['HTTP_X_UP_DEVCAP_SCREENPIXELS']) || !empty($_SERVER['HTTP_X_JPHONE_DISPLAY']) || !empty($_SERVER['HTTP_X_AVANTGO_SCREENSIZE'])) {
// AvantGo-Header dekodieren
if(!empty($_SERVER['HTTP_X_AVANTGO_SCREENSIZE'])) { $_SERVER['HTTP_X_AVANTGO_SCREENSIZE']=base64_decode($_SERVER['HTTP_X_AVANTGO_SCREENSIZE']); }
// Weitere moegliche Pixel-Header (Matches: 2 Zahlen getrennt durch Nicht-Ziffern)
if(preg_match('/([\d]*)[^\d]*([\d]*)/',@ifsetor($_SERVER['HTTP_X_UP_DEVCAP_SCREENPIXELS'],@ifsetor($_SERVER['HTTP_X_JPHONE_DISPLAY'],@ifsetor($_SERVER['HTTP_X_AVANTGO_SCREENSIZE']))),$_LOCAL_['UA_PIXELS'])) {
$_SERVER['HTTP_UA_PIXELS']=$_LOCAL_['UA_PIXELS'][1].'x'.$_LOCAL_['UA_PIXELS'][2];
}
// Zusaetzlich ggf. fehlende J-Phone/Vodafone-Farbtiefe setzen
if(!empty($_SERVER['HTTP_X_JPHONE_DISPLAY']) && empty($_SERVER['HTTP_X_JPHONE_COLOR'])) {
$_SERVER['HTTP_X_JPHONE_COLOR']='M2';
}
// Allgemeine UA-Kennung (Matches: "1024x1600" & "240x320" | Not: "16x01024" & "10240x16")
} else if(preg_match('/[\d]{3,4}x[\d]{3,4}/',$_SERVER['HTTP_USER_AGENT'],$_LOCAL_['UA_PIXELS'])) {
$_SERVER['HTTP_UA_PIXELS']=$_LOCAL_['UA_PIXELS'][0];
// iPhone-UA-Kennung
} else if(instr($_SERVER['HTTP_USER_AGENT'],array('iPhone','iPod'))) {
$_SERVER['HTTP_UA_PIXELS']=($bLandscapeMode)?'480x196':'320x356'; // Portrait-Mode ohne Keyboard (mit Keyboard: 320x140)
$_SERVER['HTTP_UA_COLOR']='color16';
// Alternativ in REQUEST definierte Daten verwenden (z.B. "?AGENT_DISPLAY=240x320x16color")
} elseif(!empty($_REQUEST['AGENT_DISPLAY'])) {
// Agent-Display-Parameter aufteilen
$_LOCAL_['AD_PARAM']=explode('x',$_REQUEST['AGENT_DISPLAY']);
// Abmessungen in Parameter 1 und 2
$_SERVER['HTTP_UA_PIXELS']=$_LOCAL_['AD_PARAM'][0].'x'.$_LOCAL_['AD_PARAM'][1];
// Bittiefe und Farbigkeit in Parameter 3
$_SERVER['HTTP_UA_COLOR']=$_LOCAL_['AD_PARAM'][2];
}
}
// Abmessungen definieren
define('AGENT_WIDTH',(!empty($_SERVER['HTTP_UA_PIXELS']))?intval($_SERVER['HTTP_UA_PIXELS']):NULL);
define('AGENT_HEIGHT',(!empty($_SERVER['HTTP_UA_PIXELS']))?intval(from($_SERVER['HTTP_UA_PIXELS'],'x',1)):NULL);
// Wenn UserAgent keine Farbinformation in HTTP_UA_COLOR sendet ...
if(AGENT_WIDTH && AGENT_HEIGHT && empty($_SERVER['HTTP_UA_COLOR'])) {
// ... Alternativen versuchen (und einheitlich in HTTP_UA_COLOR sichern):
if(!empty($_SERVER['HTTP_X_UP_DEVCAP_SCREENDEPTH'])) {
$_LOCAL_['UA_DEPTH']=intval($_SERVER['HTTP_X_UP_DEVCAP_SCREENDEPTH']);
$_SERVER['HTTP_UA_COLOR']=((@ifsetor($_SERVER['HTTP_X_UP_DEVCAP_ISCOLOR'],0,1,0))?'color':'mono').$_LOCAL_['UA_DEPTH'];
} else if(!empty($_SERVER['HTTP_X_JPHONE_COLOR'])) {
$_LOCAL_['UA_DEPTH']=strlen(decbin(intval(substr($_SERVER['HTTP_X_JPHONE_COLOR'],1))-1));
$_SERVER['HTTP_UA_COLOR']=((strtoupper($_SERVER['HTTP_X_JPHONE_COLOR'][0])=='C')?'color':'mono').$_LOCAL_['UA_DEPTH'];
// AvantGo-Alternative in $_LOCAL_['UA_DEPTH'] sichern
} else if(!empty($_SERVER['HTTP_X_AVANTGO_COLORDEPTH'])) {
$_LOCAL_['UA_DEPTH']=base64_decode($_SERVER['HTTP_X_AVANTGO_COLORDEPTH']);
// UA-Kennung (Matches: " 240x320x16" & "PPC; 16;1024x1600" & "PPC;8;320x320" | Not: "16x240x320" & "PPC128;160x64")
} else if(preg_match('/[\s|;]{1}[\d]{0,2};{0,1}[\d]{3,4}x[\d]{3,4}x{0,1}[\d]{0,2}/',$_SERVER['HTTP_USER_AGENT'],$_LOCAL_['UA_COLOR'])) {
$_LOCAL_['UA_DEPTH']=$_LOCAL_['UA_COLOR'][0];
// Alternativ in REQUEST definierte Daten verwenden (z.B. "?AGENT_DISPLAY=240x320x16color")
} elseif(!empty($_REQUEST['AGENT_DISPLAY'])) {
// Farbklassifizierung ("color"/"mono") aus REQUEST entfernen und einer neuen Kennung voranstellen
if(instr($_REQUEST['AGENT_DISPLAY'],'color',0,FALSE)) {
$_LOCAL_['UA_DEPTH']='color';
$_REQUEST['AGENT_DISPLAY']=str_replace('color','',$_REQUEST['AGENT_DISPLAY']);
} elseif(instr($_REQUEST['AGENT_DISPLAY'],'mono',0,FALSE)) {
$_LOCAL_['UA_DEPTH']='mono';
$_REQUEST['AGENT_DISPLAY']=str_replace('mono','',$_REQUEST['AGENT_DISPLAY']);
} else {
$_LOCAL_['UA_DEPTH']='';
}
$_LOCAL_['UA_DEPTH'].=$_REQUEST['AGENT_DISPLAY'];
}
// (Temporaere) Variablen vereinheitlichen
if($_LOCAL_['UA_DEPTH']) {
if($_LOCAL_['UA_DEPTH']==@ifsetor($_REQUEST['AGENT_DISPLAY'])) {
$_SERVER['HTTP_UA_COLOR']=str_replace('x','',str_replace(AGENT_WIDTH.'x'.AGENT_HEIGHT,'',$_LOCAL_['UA_DEPTH']));
$_LOCAL_['UA_DEPTH']=intval(preg_replace('/\D/','',$_SERVER['HTTP_UA_COLOR']));
} else {
$_LOCAL_['HTTP_UA_COLOR']=str_replace('x','',str_replace(AGENT_WIDTH.'x'.AGENT_HEIGHT,'',$_LOCAL_['UA_DEPTH']));
$_LOCAL_['UA_DEPTH']=intval(preg_replace('/\D/','',$_LOCAL_['UA_DEPTH']));
}
}
} else if(!empty($_SERVER['HTTP_UA_COLOR'])) {
// HTTP_UA_COLOR existiert, temporaere Variable setzen
$_LOCAL_['UA_DEPTH']=intval(preg_replace('/\D/','',$_SERVER['HTTP_UA_COLOR']));
}
// Bitanzahl des Displays definieren (wenn nicht ermittelbar: NULL)
define('AGENT_DEPTH',@ifsetor($_LOCAL_['UA_DEPTH'],NULL,'ifsetor',NULL));
// Ermitteln, ob das Display monochrome ist
if(!empty($_SERVER['HTTP_UA_COLOR'])) {
// Zuerst anhand der (im Header oder im REQUEST) vorhandenen Information ...
if(strpos($_SERVER['HTTP_UA_COLOR'],'mono')!==FALSE) {
$_LOCAL_['UA_MONO']=TRUE;
} elseif(strpos($_SERVER['HTTP_UA_COLOR'],'color')!==FALSE) {
$_LOCAL_['UA_MONO']=FALSE;
} else {
// ... ansonsten anhand der ermittelten Bitanzahl
if(AGENT_DEPTH) {
$_LOCAL_['UA_MONO']=(AGENT_DEPTH<=MONO_MAX_DEPTH);
} else {
$_LOCAL_['UA_MONO']=NULL;
}
}
} else {
$_LOCAL_['UA_MONO']=NULL;
}
// Monochrome-Status des Displays definieren (wenn nicht ermittelbar: NULL)
define('AGENT_MONO',$_LOCAL_['UA_MONO']);
// Typ (Mobilephone/PDA?) des UserAgents ermitteln (wenn nicht ermittelbar: FALSE)
define('MOBILE_AGENT',instr($_SERVER['HTTP_USER_AGENT'],$mMobileIDs,0,FALSE,TRUE) || (AGENT_WIDTH && AGENT_WIDTH<MOBILE_MAX_WIDTH) || (AGENT_HEIGHT && AGENT_HEIGHT<MOBILE_MAX_HEIGHT));
}
// ---------------------------------------------------------------------------
/**
* Zeichenkette in String enthalten? Liefert Nummer des ersten gefundenen
* Zeichens (Position+1) oder 0 im Fehlerfall.
*
* <i>int instr(string haystack, mixed needle [, int offset [, bool case-sensitive [, mixed separate [, bool all-needles]]]])</i>
*
* @version 070203
* @since 060324
* @author Cybaer <cybaer@binon.net>
* @copyright Copyright (c) 2007 Cybaer
*
* @category STRING_LIBRARY
* @access public
*
* @uses unset_array() Nur wenn $mNeedle ein Array oder aufzuteilender String ist
* @uses instr() Ggf. rekursiver Aufruf - Sucharrays werden zerlegt in mehrere instr()-Aufrufe mit Suchstring
*
* @param string $sHaystack Zu durchsuchende Zeichenkette
* @param mixed $mNeedle (string) Zu suchende Zeichenkette oder (int/double) zu suchende Zahl oder (array) Array mit Suchbegriffen
* @param int $iOffset Startposition der Suche
* @param bool $bCase Case-sensitive Suche TRUE/FALSE
* @param mixed $mExplodeNeedle (FALSE): Suchbegriff wird in Sucharray aufgeteilt wenn wahr. Enthaelt das Trennzeichen, andernfalls ist das Trennzeichen "|"
* @param bool $bAllNeedles Alle Suchbegriffe muessen enthalten sein TRUE/FALSE
* @return int Die Nummer des ersten gefundenen Zeichens (Position+1) oder 0 im Fehlerfall.
*
* Example: <code><?php
* echo instr('Die 1. IE-Version',1); // -> 5 (gesucht: "1" von Beginn an)
* echo instr('Die 1. IE-Version','IE',0); // -> 8 (gesucht: "IE" von Beginn an)
* echo instr('Die 1. IE-Version','ie',5,TRUE); // -> 0 (gesucht: "ie" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version','ie',5,FALSE); // -> 8 (gesucht: "ie", "Ie", "iE" oder "IE" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version','ie|IE',5,TRUE); // -> 0 (gesucht: "ie|IE" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version','ie|IE',5,TRUE,TRUE); // -> 8 (gesucht: "ie" oder "IE" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version','ie|IE',5,TRUE,TRUE,TRUE); // -> 0 (gesucht: "ie" und "IE" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version','ie/IE',5,TRUE,'/'); // -> 8 (gesucht: "ie" oder "IE" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version','ie IE',5,TRUE,TRUE); // -> 0 (gesucht: "ie IE" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version','ie IE',5,TRUE,' '); // -> 8 (gesucht: "ie" oder "IE" ab dem 6. Zeichen)
* echo instr('Die 1. IE-Version',array('ie','IE')); // -> 2 (gesucht: "ie" oder "IE" von Beginn an)
* ?></code>
*/
function instr($sHaystack,$mNeedle,$iOffset=0,$bCase=TRUE,$mExplodeNeedle=FALSE,$bAllNeedles=FALSE) {
// Bei case-insensitive Suche den zu durchsuchenden String in Kleinbuchstaben wandeln
if(!$bCase) { $sHaystack=strtolower($sHaystack); }
// Mehrere moegliche Zeichenketten in einem String uebergeben
if($mExplodeNeedle!==FALSE && is_string($mNeedle)) {
// Wurde Trennzeichen uebergeben?
if(is_string($mExplodeNeedle) && strlen($mExplodeNeedle)) {
// Ja: String an uebergebenem Trennzeichen aufteilen
$mNeedle=explode($mExplodeNeedle,$mNeedle);
} elseif($mExplodeNeedle!==NULL) {
// Nein: String an Default-Trennzeichen aufteilen (keine leeren Eintraege)
$mNeedle=explode('|',$mNeedle);
}
}
// Mehrere moegliche Zeichenketten in einem Array uebergeben?
if(is_array($mNeedle)) {
$iResult=0; $iCount=0;
// Leere Sucheintraege entfernen
$mNeedle=unset_array($mNeedle,'');
// Ja: Array-Eintraege durchgehen
foreach($mNeedle as $mSearch) {
// Eintrag suchen (kann wieder Array sein)
$iSearch=instr($sHaystack,$mSearch,$iOffset,$bCase);
// Bei Erfolg:
if($iSearch) {
// Wenn alle Needles gefunden werden muessen
if($bAllNeedles) {
// Zaehler erhoehen ...
$iCount++;
// ... und erste Fundstelle sichern
if($iCount==1) { $iResult=$iSearch; }
} else {
// Wenn nur eine Needle gefunden werden muss: Fundstelle sichern
$iResult=$iSearch;
// Suche abbrechen
break;
}
} else if($bAllNeedles) {
// Needle nicht gefunden obwohl verlangt: Abbruch
break;
}
}
// Wirklich alle gefunden?
if($bAllNeedles && $iCount<sizeof($mNeedle)) { $iResult=0; }
} else {
// Kein Array als Needle uebergeben: Datentyp auf String setzen
settype($mNeedle,'string');
// Bei leerem String ...
if($mNeedle=='') {
// ... erst gar nicht suchen
$iResult=0;
} else {
// Bei case-insensitive Suche den Suchstring in Kleinbuchstaben wandeln
if(!$bCase) { $mNeedle=strtolower($mNeedle); }
// Suchergebnis merken
$iResult=strpos($sHaystack,$mNeedle,$iOffset);
// Ergebnis ist 0 bei Nichterfolg und Position des Suchstrings +1 bei Erfolg
$iResult=($iResult===FALSE)?0:$iResult+1;
}
}
return $iResult;
}
// ---------------------------------------------------------------------------
/* Gebe Variableninhalt oder Alternative zurueck (bei ggf. nicht existenten Variablen mit @ aufrufen!) 060323/060506 */
function ifsetor($mContent,$mNullReturn='',$mTrueReturn='ifsetor',$mFalseReturn='ifsetor') {
if($mContent===NULL) {
return $mNullReturn;
} elseif($mContent) {
return ($mTrueReturn!='ifsetor')?$mTrueReturn:$mContent;
} else {
return ($mFalseReturn!='ifsetor')?$mFalseReturn:$mContent;
}
}
// ---------------------------------------------------------------------------
/* Loeschen eines Eintrags aus einem Array 060325/061106 */
function unset_array($aHaystack,$mNeedle,$bStrict=FALSE,$bRebuildNumArray=FALSE) {
$aResult=array();
$iCount=0;
foreach($aHaystack as $sKey => $mValue) {
if($bStrict) {
if($mValue!==$mNeedle) { $aResult[($bRebuildNumArray)?$iCount:$sKey]=$mValue; $iCount++; }
} else {
if($mValue!=$mNeedle) { $aResult[($bRebuildNumArray)?$iCount:$sKey]=$mValue; $iCount++; }
}
}
return $aResult;
}
// ---------------------------------------------------------------------------
/* Hole String ab needle */
function from($haystack,$needle,$offset=0) {
$result=strpos($haystack,$needle);
$result=substr($haystack,$result+$offset);
return $result;
}
?>