| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344 | <?php/** * phpQuery is a server-side, chainable, CSS3 selector driven * Document Object Model (DOM) API based on jQuery JavaScript Library. * * @version 0.9.5 * @link http://code.google.com/p/phpquery/ * @link http://phpquery-library.blogspot.com/ * @link http://jquery.com/ * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> * @license http://www.opensource.org/licenses/mit-license.php MIT License * @package phpQuery */// class names for instanceof// TODO move them as class constants into phpQuerydefine('DOMDOCUMENT', 'DOMDocument');define('DOMELEMENT', 'DOMElement');define('DOMNODELIST', 'DOMNodeList');define('DOMNODE', 'DOMNode');require_once(dirname(__FILE__).'/phpQuery/DOMEvent.php');require_once(dirname(__FILE__).'/phpQuery/DOMDocumentWrapper.php');require_once(dirname(__FILE__).'/phpQuery/phpQueryEvents.php');require_once(dirname(__FILE__).'/phpQuery/Callback.php');require_once(dirname(__FILE__).'/phpQuery/phpQueryObject.php');require_once(dirname(__FILE__).'/phpQuery/compat/mbstring.php');/** * Static namespace for phpQuery functions. * * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> * @package phpQuery */abstract class phpQuery {	/**	 * XXX: Workaround for mbstring problems 	 * 	 * @var bool	 */	public static $mbstringSupport = true;	public static $debug = false;	public static $documents = array();	public static $defaultDocumentID = null;//	public static $defaultDoctype = 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"';	/**	 * Applies only to HTML.	 *	 * @var unknown_type	 */	public static $defaultDoctype = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">';	public static $defaultCharset = 'UTF-8';	/**	 * Static namespace for plugins.	 *	 * @var object	 */	public static $plugins = array();	/**	 * List of loaded plugins.	 *	 * @var unknown_type	 */	public static $pluginsLoaded = array();	public static $pluginsMethods = array();	public static $pluginsStaticMethods = array();	public static $extendMethods = array();	/**	 * @TODO implement	 */	public static $extendStaticMethods = array();	/**	 * Hosts allowed for AJAX connections.	 * Dot '.' means $_SERVER['HTTP_HOST'] (if any).	 *	 * @var array	 */	public static $ajaxAllowedHosts = array(		'.'	);	/**	 * AJAX settings.	 *	 * @var array	 * XXX should it be static or not ?	 */	public static $ajaxSettings = array(		'url' => '',//TODO		'global' => true,		'type' => "GET",		'timeout' => null,		'contentType' => "application/x-www-form-urlencoded",		'processData' => true,//		'async' => true,		'data' => null,		'username' => null,		'password' => null,		'dataType' => null,		'ifModified' => null,		'accepts' => array(			'xml' => "application/xml, text/xml",			'html' => "text/html",			'script' => "text/javascript, application/javascript",			'json' => "application/json, text/javascript",			'text' => "text/plain",			'_default' => "*/*"		)	);	public static $lastModified = null;	public static $active = 0;	public static $dumpCount = 0;	/**	 * Multi-purpose function.	 * Use pq() as shortcut.	 *	 * In below examples, $pq is any result of pq(); function.	 *	 * 1. Import markup into existing document (without any attaching):	 * - Import into selected document:	 *   pq('<div/>')				// DOESNT accept text nodes at beginning of input string !	 * - Import into document with ID from $pq->getDocumentID():	 *   pq('<div/>', $pq->getDocumentID())	 * - Import into same document as DOMNode belongs to:	 *   pq('<div/>', DOMNode)	 * - Import into document from phpQuery object:	 *   pq('<div/>', $pq)	 *	 * 2. Run query:	 * - Run query on last selected document:	 *   pq('div.myClass')	 * - Run query on document with ID from $pq->getDocumentID():	 *   pq('div.myClass', $pq->getDocumentID())	 * - Run query on same document as DOMNode belongs to and use node(s)as root for query:	 *   pq('div.myClass', DOMNode)	 * - Run query on document from phpQuery object	 *   and use object's stack as root node(s) for query:	 *   pq('div.myClass', $pq)	 *	 * @param string|DOMNode|DOMNodeList|array	$arg1	HTML markup, CSS Selector, DOMNode or array of DOMNodes	 * @param string|phpQueryObject|DOMNode	$context	DOM ID from $pq->getDocumentID(), phpQuery object (determines also query root) or DOMNode (determines also query root)	 *	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery|QueryTemplatesPhpQuery|false   * phpQuery object or false in case of error.	 */	public static function pq($arg1, $context = null) {		if ($arg1 instanceof DOMNODE && ! isset($context)) {			foreach(phpQuery::$documents as $documentWrapper) {				$compare = $arg1 instanceof DOMDocument					? $arg1 : $arg1->ownerDocument;				if ($documentWrapper->document->isSameNode($compare))					$context = $documentWrapper->id;			}		}		if (! $context) {			$domId = self::$defaultDocumentID;			if (! $domId)				throw new Exception("Can't use last created DOM, because there isn't any. Use phpQuery::newDocument() first.");//		} else if (is_object($context) && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject')))		} else if (is_object($context) && $context instanceof phpQueryObject)			$domId = $context->getDocumentID();		else if ($context instanceof DOMDOCUMENT) {			$domId = self::getDocumentID($context);			if (! $domId) {				//throw new Exception('Orphaned DOMDocument');				$domId = self::newDocument($context)->getDocumentID();			}		} else if ($context instanceof DOMNODE) {			$domId = self::getDocumentID($context);			if (! $domId) {				throw new Exception('Orphaned DOMNode');//				$domId = self::newDocument($context->ownerDocument);			}		} else			$domId = $context;		if ($arg1 instanceof phpQueryObject) {//		if (is_object($arg1) && (get_class($arg1) == 'phpQueryObject' || $arg1 instanceof PHPQUERY || is_subclass_of($arg1, 'phpQueryObject'))) {			/**			 * Return $arg1 or import $arg1 stack if document differs:			 * pq(pq('<div/>'))			 */			if ($arg1->getDocumentID() == $domId)				return $arg1;			$class = get_class($arg1);			// support inheritance by passing old object to overloaded constructor			$phpQuery = $class != 'phpQuery'				? new $class($arg1, $domId)				: new phpQueryObject($domId);			$phpQuery->elements = array();			foreach($arg1->elements as $node)				$phpQuery->elements[] = $phpQuery->document->importNode($node, true);			return $phpQuery;		} else if ($arg1 instanceof DOMNODE || (is_array($arg1) && isset($arg1[0]) && $arg1[0] instanceof DOMNODE)) {			/*			 * Wrap DOM nodes with phpQuery object, import into document when needed:			 * pq(array($domNode1, $domNode2))			 */			$phpQuery = new phpQueryObject($domId);			if (!($arg1 instanceof DOMNODELIST) && ! is_array($arg1))				$arg1 = array($arg1);			$phpQuery->elements = array();			foreach($arg1 as $node) {				$sameDocument = $node->ownerDocument instanceof DOMDOCUMENT					&& ! $node->ownerDocument->isSameNode($phpQuery->document);				$phpQuery->elements[] = $sameDocument					? $phpQuery->document->importNode($node, true)					: $node;			}			return $phpQuery;		} else if (self::isMarkup($arg1)) {			/**			 * Import HTML:			 * pq('<div/>')			 */			$phpQuery = new phpQueryObject($domId);			return $phpQuery->newInstance(				$phpQuery->documentWrapper->import($arg1)			);		} else {			/**			 * Run CSS query:			 * pq('div.myClass')			 */			$phpQuery = new phpQueryObject($domId);//			if ($context && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject')))			if ($context && $context instanceof phpQueryObject)				$phpQuery->elements = $context->elements;			else if ($context && $context instanceof DOMNODELIST) {				$phpQuery->elements = array();				foreach($context as $node)					$phpQuery->elements[] = $node;			} else if ($context && $context instanceof DOMNODE)				$phpQuery->elements = array($context);			return $phpQuery->find($arg1);		}	}	/**	 * Sets default document to $id. Document has to be loaded prior	 * to using this method.	 * $id can be retrived via getDocumentID() or getDocumentIDRef().	 *	 * @param unknown_type $id	 */	public static function selectDocument($id) {		$id = self::getDocumentID($id);		self::debug("Selecting document '$id' as default one");		self::$defaultDocumentID = self::getDocumentID($id);	}	/**	 * Returns document with id $id or last used as phpQueryObject.	 * $id can be retrived via getDocumentID() or getDocumentIDRef().	 * Chainable.	 *	 * @see phpQuery::selectDocument()	 * @param unknown_type $id	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function getDocument($id = null) {		if ($id)			phpQuery::selectDocument($id);		else			$id = phpQuery::$defaultDocumentID;		return new phpQueryObject($id);	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocument($markup = null, $contentType = null) {		if (! $markup)			$markup = '';		$documentID = phpQuery::createDocumentWrapper($markup, $contentType);		return new phpQueryObject($documentID);	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentHTML($markup = null, $charset = null) {		$contentType = $charset			? ";charset=$charset"			: '';		return self::newDocument($markup, "text/html{$contentType}");	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentXML($markup = null, $charset = null) {		$contentType = $charset			? ";charset=$charset"			: '';		return self::newDocument($markup, "text/xml{$contentType}");	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentXHTML($markup = null, $charset = null) {		$contentType = $charset			? ";charset=$charset"			: '';		return self::newDocument($markup, "application/xhtml+xml{$contentType}");	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentPHP($markup = null, $contentType = "text/html") {		// TODO pass charset to phpToMarkup if possible (use DOMDocumentWrapper function)		$markup = phpQuery::phpToMarkup($markup, self::$defaultCharset);		return self::newDocument($markup, $contentType);	}	public static function phpToMarkup($php, $charset = 'utf-8') {		$regexes = array(			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)<'.'?php?(.*?)(?:\\?>)([^\']*)\'@s',			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)<'.'?php?(.*?)(?:\\?>)([^"]*)"@s',		);		foreach($regexes as $regex)			while (preg_match($regex, $php, $matches)) {				$php = preg_replace_callback(					$regex,//					create_function('$m, $charset = "'.$charset.'"',//						'return $m[1].$m[2]//							.htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset)//							.$m[5].$m[2];'//					),					array('phpQuery', '_phpToMarkupCallback'),					$php				);			}		$regex = '@(^|>[^<]*)+?(<\?php(.*?)(\?>))@s';//preg_match_all($regex, $php, $matches);//var_dump($matches);		$php = preg_replace($regex, '\\1<php><!-- \\3 --></php>', $php);		return $php;	}	public static function _phpToMarkupCallback($php, $charset = 'utf-8') {		return $m[1].$m[2]			.htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset)			.$m[5].$m[2];	}	public static function _markupToPHPCallback($m) {		return "<"."?php ".htmlspecialchars_decode($m[1])." ?".">";	}	/**	 * Converts document markup containing PHP code generated by phpQuery::php()	 * into valid (executable) PHP code syntax.	 *	 * @param string|phpQueryObject $content	 * @return string PHP code.	 */	public static function markupToPHP($content) {		if ($content instanceof phpQueryObject)			$content = $content->markupOuter();		/* <php>...</php> to <?php...? > */		$content = preg_replace_callback(			'@<php>\s*<!--(.*?)-->\s*</php>@s',//			create_function('$m',//				'return "<'.'?php ".htmlspecialchars_decode($m[1])." ?'.'>";'//			),			array('phpQuery', '_markupToPHPCallback'),			$content		);		/* <node attr='< ?php ? >'> extra space added to save highlighters */		$regexes = array(			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^\']*)\'@s',			'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^"]*)"@s',		);		foreach($regexes as $regex)			while (preg_match($regex, $content))				$content = preg_replace_callback(					$regex,					create_function('$m',						'return $m[1].$m[2].$m[3]."<?php "							.str_replace(								array("%20", "%3E", "%09", "
", "	", "%7B", "%24", "%7D", "%22", "%5B", "%5D"),								array(" ", ">", "	", "\n", "	", "{", "$", "}", \'"\', "[", "]"),								htmlspecialchars_decode($m[4])							)							." ?>".$m[5].$m[2];'					),					$content				);		return $content;	}	/**	 * Creates new document from file $file.	 * Chainable.	 *	 * @param string $file URLs allowed. See File wrapper page at php.net for more supported sources.	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentFile($file, $contentType = null) {		$documentID = self::createDocumentWrapper(			file_get_contents($file), $contentType		);		return new phpQueryObject($documentID);	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentFileHTML($file, $charset = null) {		$contentType = $charset			? ";charset=$charset"			: '';		return self::newDocumentFile($file, "text/html{$contentType}");	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentFileXML($file, $charset = null) {		$contentType = $charset			? ";charset=$charset"			: '';		return self::newDocumentFile($file, "text/xml{$contentType}");	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentFileXHTML($file, $charset = null) {		$contentType = $charset			? ";charset=$charset"			: '';		return self::newDocumentFile($file, "application/xhtml+xml{$contentType}");	}	/**	 * Creates new document from markup.	 * Chainable.	 *	 * @param unknown_type $markup	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 */	public static function newDocumentFilePHP($file, $contentType = null) {		return self::newDocumentPHP(file_get_contents($file), $contentType);	}	/**	 * Reuses existing DOMDocument object.	 * Chainable.	 *	 * @param $document DOMDocument	 * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery	 * @TODO support DOMDocument	 */	public static function loadDocument($document) {		// TODO		die('TODO loadDocument');	}	/**	 * Enter description here...	 *	 * @param unknown_type $html	 * @param unknown_type $domId	 * @return unknown New DOM ID	 * @todo support PHP tags in input	 * @todo support passing DOMDocument object from self::loadDocument	 */	protected static function createDocumentWrapper($html, $contentType = null, $documentID = null) {		if (function_exists('domxml_open_mem'))			throw new Exception("Old PHP4 DOM XML extension detected. phpQuery won't work until this extension is enabled.");//		$id = $documentID//			? $documentID//			: md5(microtime());		$document = null;		if ($html instanceof DOMDOCUMENT) {			if (self::getDocumentID($html)) {				// document already exists in phpQuery::$documents, make a copy				$document = clone $html;			} else {				// new document, add it to phpQuery::$documents				$wrapper = new DOMDocumentWrapper($html, $contentType, $documentID);			}		} else {			$wrapper = new DOMDocumentWrapper($html, $contentType, $documentID);		}//		$wrapper->id = $id;		// bind document		phpQuery::$documents[$wrapper->id] = $wrapper;		// remember last loaded document		phpQuery::selectDocument($wrapper->id);		return $wrapper->id;	}	/**	 * Extend class namespace.	 *	 * @param string|array $target	 * @param array $source	 * @TODO support string $source	 * @return unknown_type	 */	public static function extend($target, $source) {		switch($target) {			case 'phpQueryObject':				$targetRef = &self::$extendMethods;				$targetRef2 = &self::$pluginsMethods;				break;			case 'phpQuery':				$targetRef = &self::$extendStaticMethods;				$targetRef2 = &self::$pluginsStaticMethods;				break;			default:				throw new Exception("Unsupported \$target type");		}		if (is_string($source))			$source = array($source => $source);		foreach($source as $method => $callback) {			if (isset($targetRef[$method])) {//				throw new Exception				self::debug("Duplicate method '{$method}', can\'t extend '{$target}'");				continue;			}			if (isset($targetRef2[$method])) {//				throw new Exception				self::debug("Duplicate method '{$method}' from plugin '{$targetRef2[$method]}',"					." can\'t extend '{$target}'");				continue;			}			$targetRef[$method] = $callback;		}		return true;	}	/**	 * Extend phpQuery with $class from $file.	 *	 * @param string $class Extending class name. Real class name can be prepended phpQuery_.	 * @param string $file Filename to include. Defaults to "{$class}.php".	 */	public static function plugin($class, $file = null) {		// TODO $class checked agains phpQuery_$class//		if (strpos($class, 'phpQuery') === 0)//			$class = substr($class, 8);		if (in_array($class, self::$pluginsLoaded))			return true;		if (! $file)			$file = $class.'.php';		$objectClassExists = class_exists('phpQueryObjectPlugin_'.$class);		$staticClassExists = class_exists('phpQueryPlugin_'.$class);		if (! $objectClassExists && ! $staticClassExists)			require_once($file);		self::$pluginsLoaded[] = $class;		// static methods		if (class_exists('phpQueryPlugin_'.$class)) {			$realClass = 'phpQueryPlugin_'.$class;			$vars = get_class_vars($realClass);			$loop = isset($vars['phpQueryMethods'])				&& ! is_null($vars['phpQueryMethods'])				? $vars['phpQueryMethods']				: get_class_methods($realClass);			foreach($loop as $method) {				if ($method == '__initialize')					continue;				if (! is_callable(array($realClass, $method)))					continue;				if (isset(self::$pluginsStaticMethods[$method])) {					throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsStaticMethods[$method]."'");					return;				}				self::$pluginsStaticMethods[$method] = $class;			}			if (method_exists($realClass, '__initialize'))				call_user_func_array(array($realClass, '__initialize'), array());		}		// object methods		if (class_exists('phpQueryObjectPlugin_'.$class)) {			$realClass = 'phpQueryObjectPlugin_'.$class;			$vars = get_class_vars($realClass);			$loop = isset($vars['phpQueryMethods'])				&& ! is_null($vars['phpQueryMethods'])				? $vars['phpQueryMethods']				: get_class_methods($realClass);			foreach($loop as $method) {				if (! is_callable(array($realClass, $method)))					continue;				if (isset(self::$pluginsMethods[$method])) {					throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsMethods[$method]."'");					continue;				}				self::$pluginsMethods[$method] = $class;			}		}		return true;	}	/**	 * Unloades all or specified document from memory.	 *	 * @param mixed $documentID @see phpQuery::getDocumentID() for supported types.	 */	public static function unloadDocuments($id = null) {		if (isset($id)) {			if ($id = self::getDocumentID($id))				unset(phpQuery::$documents[$id]);		} else {			foreach(phpQuery::$documents as $k => $v) {				unset(phpQuery::$documents[$k]);			}		}	}	/**	 * Parses phpQuery object or HTML result against PHP tags and makes them active.	 *	 * @param phpQuery|string $content	 * @deprecated	 * @return string	 */	public static function unsafePHPTags($content) {		return self::markupToPHP($content);	}	public static function DOMNodeListToArray($DOMNodeList) {		$array = array();		if (! $DOMNodeList)			return $array;		foreach($DOMNodeList as $node)			$array[] = $node;		return $array;	}	/**	 * Checks if $input is HTML string, which has to start with '<'.	 *	 * @deprecated	 * @param String $input	 * @return Bool	 * @todo still used ?	 */	public static function isMarkup($input) {		return ! is_array($input) && substr(trim($input), 0, 1) == '<';	}	public static function debug($text) {		if (self::$debug)			print var_dump($text);	}	/**	 * Make an AJAX request.	 *	 * @param array See $options http://docs.jquery.com/Ajax/jQuery.ajax#toptions	 * Additional options are:	 * 'document' - document for global events, @see phpQuery::getDocumentID()	 * 'referer' - implemented	 * 'requested_with' - TODO; not implemented (X-Requested-With)	 * @return Zend_Http_Client	 * @link http://docs.jquery.com/Ajax/jQuery.ajax	 *	 * @TODO $options['cache']	 * @TODO $options['processData']	 * @TODO $options['xhr']	 * @TODO $options['data'] as string	 * @TODO XHR interface	 */	public static function ajax($options = array(), $xhr = null) {		$options = array_merge(			self::$ajaxSettings, $options		);		$documentID = isset($options['document'])			? self::getDocumentID($options['document'])			: null;		if ($xhr) {			// reuse existing XHR object, but clean it up			$client = $xhr;//			$client->setParameterPost(null);//			$client->setParameterGet(null);			$client->setAuth(false);			$client->setHeaders("If-Modified-Since", null);			$client->setHeaders("Referer", null);			$client->resetParameters();		} else {			// create new XHR object			require_once('Zend/Http/Client.php');			$client = new Zend_Http_Client();			$client->setCookieJar();		}		if (isset($options['timeout']))			$client->setConfig(array(				'timeout'      => $options['timeout'],			));//			'maxredirects' => 0,		foreach(self::$ajaxAllowedHosts as $k => $host)			if ($host == '.' && isset($_SERVER['HTTP_HOST']))				self::$ajaxAllowedHosts[$k] = $_SERVER['HTTP_HOST'];		$host = parse_url($options['url'], PHP_URL_HOST);		if (! in_array($host, self::$ajaxAllowedHosts)) {			throw new Exception("Request not permitted, host '$host' not present in "				."phpQuery::\$ajaxAllowedHosts");		}		// JSONP		$jsre = "/=\\?(&|$)/";		if (isset($options['dataType']) && $options['dataType'] == 'jsonp') {			$jsonpCallbackParam = $options['jsonp']				? $options['jsonp'] : 'callback';			if (strtolower($options['type']) == 'get') {				if (! preg_match($jsre, $options['url'])) {					$sep = strpos($options['url'], '?')						? '&' : '?';					$options['url'] .= "$sep$jsonpCallbackParam=?";				}			} else if ($options['data']) {				$jsonp = false;				foreach($options['data'] as $n => $v) {					if ($v == '?')						$jsonp = true;				}				if (! $jsonp) {					$options['data'][$jsonpCallbackParam] = '?';				}			}			$options['dataType'] = 'json';		}		if (isset($options['dataType']) && $options['dataType'] == 'json') {			$jsonpCallback = 'json_'.md5(microtime());			$jsonpData = $jsonpUrl = false;			if ($options['data']) {				foreach($options['data'] as $n => $v) {					if ($v == '?')						$jsonpData = $n;				}			}			if (preg_match($jsre, $options['url']))				$jsonpUrl = true;			if ($jsonpData !== false || $jsonpUrl) {				// remember callback name for httpData()				$options['_jsonp'] = $jsonpCallback;				if ($jsonpData !== false)					$options['data'][$jsonpData] = $jsonpCallback;				if ($jsonpUrl)					$options['url'] = preg_replace($jsre, "=$jsonpCallback\\1", $options['url']);			}		}		$client->setUri($options['url']);		$client->setMethod(strtoupper($options['type']));		if (isset($options['referer']) && $options['referer'])			$client->setHeaders('Referer', $options['referer']);		$client->setHeaders(array(//			'content-type' => $options['contentType'],			'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86; en-US; rv:1.9.0.5) Gecko'				 .'/2008122010 Firefox/3.0.5',	 		// TODO custom charset			'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',// 	 		'Connection' => 'keep-alive',// 			'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',	 		'Accept-Language' => 'en-us,en;q=0.5',		));		if ($options['username'])			$client->setAuth($options['username'], $options['password']);		if (isset($options['ifModified']) && $options['ifModified'])			$client->setHeaders("If-Modified-Since",				self::$lastModified					? self::$lastModified					: "Thu, 01 Jan 1970 00:00:00 GMT"			);		$client->setHeaders("Accept",			isset($options['dataType'])			&& isset(self::$ajaxSettings['accepts'][ $options['dataType'] ])				? self::$ajaxSettings['accepts'][ $options['dataType'] ].", */*"				: self::$ajaxSettings['accepts']['_default']		);		// TODO $options['processData']		if ($options['data'] instanceof phpQueryObject) {			$serialized = $options['data']->serializeArray($options['data']);			$options['data'] = array();			foreach($serialized as $r)				$options['data'][ $r['name'] ] = $r['value'];		}		if (strtolower($options['type']) == 'get') {			$client->setParameterGet($options['data']);		} else if (strtolower($options['type']) == 'post') {			$client->setEncType($options['contentType']);			$client->setParameterPost($options['data']);		}		if (self::$active == 0 && $options['global'])			phpQueryEvents::trigger($documentID, 'ajaxStart');		self::$active++;		// beforeSend callback		if (isset($options['beforeSend']) && $options['beforeSend'])			phpQuery::callbackRun($options['beforeSend'], array($client));		// ajaxSend event		if ($options['global'])			phpQueryEvents::trigger($documentID, 'ajaxSend', array($client, $options));		if (phpQuery::$debug) {			self::debug("{$options['type']}: {$options['url']}\n");			self::debug("Options: <pre>".var_export($options, true)."</pre>\n");//			if ($client->getCookieJar())//				self::debug("Cookies: <pre>".var_export($client->getCookieJar()->getMatchingCookies($options['url']), true)."</pre>\n");		}		// request		$response = $client->request();		if (phpQuery::$debug) {			self::debug('Status: '.$response->getStatus().' / '.$response->getMessage());			self::debug($client->getLastRequest());			self::debug($response->getHeaders());		}		if ($response->isSuccessful()) {			// XXX tempolary			self::$lastModified = $response->getHeader('Last-Modified');			$data = self::httpData($response->getBody(), $options['dataType'], $options);			if (isset($options['success']) && $options['success'])				phpQuery::callbackRun($options['success'], array($data, $response->getStatus(), $options));			if ($options['global'])				phpQueryEvents::trigger($documentID, 'ajaxSuccess', array($client, $options));		} else {			if (isset($options['error']) && $options['error'])				phpQuery::callbackRun($options['error'], array($client, $response->getStatus(), $response->getMessage()));			if ($options['global'])				phpQueryEvents::trigger($documentID, 'ajaxError', array($client, /*$response->getStatus(),*/$response->getMessage(), $options));		}		if (isset($options['complete']) && $options['complete'])			phpQuery::callbackRun($options['complete'], array($client, $response->getStatus()));		if ($options['global'])			phpQueryEvents::trigger($documentID, 'ajaxComplete', array($client, $options));		if ($options['global'] && ! --self::$active)			phpQueryEvents::trigger($documentID, 'ajaxStop');		return $client;//		if (is_null($domId))//			$domId = self::$defaultDocumentID ? self::$defaultDocumentID : false;//		return new phpQueryAjaxResponse($response, $domId);	}	protected static function httpData($data, $type, $options) {		if (isset($options['dataFilter']) && $options['dataFilter'])			$data = self::callbackRun($options['dataFilter'], array($data, $type));		if (is_string($data)) {			if ($type == "json") {				if (isset($options['_jsonp']) && $options['_jsonp']) {					$data = preg_replace('/^\s*\w+\((.*)\)\s*$/s', '$1', $data);				}				$data = self::parseJSON($data);			}		}		return $data;	}	/**	 * Enter description here...	 *	 * @param array|phpQuery $data	 *	 */	public static function param($data) {		return http_build_query($data, null, '&');	}	public static function get($url, $data = null, $callback = null, $type = null) {		if (!is_array($data)) {			$callback = $data;			$data = null;		}		// TODO some array_values on this shit		return phpQuery::ajax(array(			'type' => 'GET',			'url' => $url,			'data' => $data,			'success' => $callback,			'dataType' => $type,		));	}	public static function post($url, $data = null, $callback = null, $type = null) {		if (!is_array($data)) {			$callback = $data;			$data = null;		}		return phpQuery::ajax(array(			'type' => 'POST',			'url' => $url,			'data' => $data,			'success' => $callback,			'dataType' => $type,		));	}	public static function getJSON($url, $data = null, $callback = null) {		if (!is_array($data)) {			$callback = $data;			$data = null;		}		// TODO some array_values on this shit		return phpQuery::ajax(array(			'type' => 'GET',			'url' => $url,			'data' => $data,			'success' => $callback,			'dataType' => 'json',		));	}	public static function ajaxSetup($options) {		self::$ajaxSettings = array_merge(			self::$ajaxSettings,			$options		);	}	public static function ajaxAllowHost($host1, $host2 = null, $host3 = null) {		$loop = is_array($host1)			? $host1			: func_get_args();		foreach($loop as $host) {			if ($host && ! in_array($host, phpQuery::$ajaxAllowedHosts)) {				phpQuery::$ajaxAllowedHosts[] = $host;			}		}	}	public static function ajaxAllowURL($url1, $url2 = null, $url3 = null) {		$loop = is_array($url1)			? $url1			: func_get_args();		foreach($loop as $url)			phpQuery::ajaxAllowHost(parse_url($url, PHP_URL_HOST));	}	/**	 * Returns JSON representation of $data.	 *	 * @static	 * @param mixed $data	 * @return string	 */	public static function toJSON($data) {		if (function_exists('json_encode'))			return json_encode($data);		require_once('Zend/Json/Encoder.php');		return Zend_Json_Encoder::encode($data);	}	/**	 * Parses JSON into proper PHP type.	 *	 * @static	 * @param string $json	 * @return mixed	 */	public static function parseJSON($json) {		if (function_exists('json_decode')) {			$return = json_decode(trim($json), true);			// json_decode and UTF8 issues			if (isset($return))				return $return;		}		require_once('Zend/Json/Decoder.php');		return Zend_Json_Decoder::decode($json);	}	/**	 * Returns source's document ID.	 *	 * @param $source DOMNode|phpQueryObject	 * @return string	 */	public static function getDocumentID($source) {		if ($source instanceof DOMDOCUMENT) {			foreach(phpQuery::$documents as $id => $document) {				if ($source->isSameNode($document->document))					return $id;			}		} else if ($source instanceof DOMNODE) {			foreach(phpQuery::$documents as $id => $document) {				if ($source->ownerDocument->isSameNode($document->document))					return $id;			}		} else if ($source instanceof phpQueryObject)			return $source->getDocumentID();		else if (is_string($source) && isset(phpQuery::$documents[$source]))			return $source;	}	/**	 * Get DOMDocument object related to $source.	 * Returns null if such document doesn't exist.	 *	 * @param $source DOMNode|phpQueryObject|string	 * @return string	 */	public static function getDOMDocument($source) {		if ($source instanceof DOMDOCUMENT)			return $source;		$source = self::getDocumentID($source);		return $source			? self::$documents[$id]['document']			: null;	}	// UTILITIES	// http://docs.jquery.com/Utilities	/**	 *	 * @return unknown_type	 * @link http://docs.jquery.com/Utilities/jQuery.makeArray	 */	public static function makeArray($obj) {		$array = array();		if (is_object($object) && $object instanceof DOMNODELIST) {			foreach($object as $value)				$array[] = $value;		} else if (is_object($object) && ! ($object instanceof Iterator)) {			foreach(get_object_vars($object) as $name => $value)				$array[0][$name] = $value;		} else {			foreach($object as $name => $value)				$array[0][$name] = $value;		}		return $array;	}	public static function inArray($value, $array) {		return in_array($value, $array);	}	/**	 *	 * @param $object	 * @param $callback	 * @return unknown_type	 * @link http://docs.jquery.com/Utilities/jQuery.each	 */	public static function each($object, $callback, $param1 = null, $param2 = null, $param3 = null) {		$paramStructure = null;		if (func_num_args() > 2) {			$paramStructure = func_get_args();			$paramStructure = array_slice($paramStructure, 2);		}		if (is_object($object) && ! ($object instanceof Iterator)) {			foreach(get_object_vars($object) as $name => $value)				phpQuery::callbackRun($callback, array($name, $value), $paramStructure);		} else {			foreach($object as $name => $value)				phpQuery::callbackRun($callback, array($name, $value), $paramStructure);		}	}	/**	 *	 * @link http://docs.jquery.com/Utilities/jQuery.map	 */	public static function map($array, $callback, $param1 = null, $param2 = null, $param3 = null) {		$result = array();		$paramStructure = null;		if (func_num_args() > 2) {			$paramStructure = func_get_args();			$paramStructure = array_slice($paramStructure, 2);		}		foreach($array as $v) {			$vv = phpQuery::callbackRun($callback, array($v), $paramStructure);//			$callbackArgs = $args;//			foreach($args as $i => $arg) {//				$callbackArgs[$i] = $arg instanceof CallbackParam//					? $v//					: $arg;//			}//			$vv = call_user_func_array($callback, $callbackArgs);			if (is_array($vv))  {				foreach($vv as $vvv)					$result[] = $vvv;			} else if ($vv !== null) {				$result[] = $vv;			}		}		return $result;	}	/**	 *	 * @param $callback Callback	 * @param $params	 * @param $paramStructure	 * @return unknown_type	 */	public static function callbackRun($callback, $params = array(), $paramStructure = null) {		if (! $callback)			return;		if ($callback instanceof CallbackParameterToReference) {			// TODO support ParamStructure to select which $param push to reference			if (isset($params[0]))				$callback->callback = $params[0];			return true;		}		if ($callback instanceof Callback) {			$paramStructure = $callback->params;			$callback = $callback->callback;		}		if (! $paramStructure)			return call_user_func_array($callback, $params);		$p = 0;		foreach($paramStructure as $i => $v) {			$paramStructure[$i] = $v instanceof CallbackParam				? $params[$p++]				: $v;		}		return call_user_func_array($callback, $paramStructure);	}	/**	 * Merge 2 phpQuery objects.	 * @param array $one	 * @param array $two	 * @protected	 * @todo node lists, phpQueryObject	 */	public static function merge($one, $two) {		$elements = $one->elements;		foreach($two->elements as $node) {			$exists = false;			foreach($elements as $node2) {				if ($node2->isSameNode($node))					$exists = true;			}			if (! $exists)				$elements[] = $node;		}		return $elements;//		$one = $one->newInstance();//		$one->elements = $elements;//		return $one;	}	/**	 *	 * @param $array	 * @param $callback	 * @param $invert	 * @return unknown_type	 * @link http://docs.jquery.com/Utilities/jQuery.grep	 */	public static function grep($array, $callback, $invert = false) {		$result = array();		foreach($array as $k => $v) {			$r = call_user_func_array($callback, array($v, $k));			if ($r === !(bool)$invert)				$result[] = $v;		}		return $result;	}	public static function unique($array) {		return array_unique($array);	}	/**	 *	 * @param $function	 * @return unknown_type	 * @TODO there are problems with non-static methods, second parameter pass it	 * 	but doesnt verify is method is really callable	 */	public static function isFunction($function) {		return is_callable($function);	}	public static function trim($str) {		return trim($str);	}	/* PLUGINS NAMESPACE */	/**	 *	 * @param $url	 * @param $callback	 * @param $param1	 * @param $param2	 * @param $param3	 * @return phpQueryObject	 */	public static function browserGet($url, $callback, $param1 = null, $param2 = null, $param3 = null) {		if (self::plugin('WebBrowser')) {			$params = func_get_args();			return self::callbackRun(array(self::$plugins, 'browserGet'), $params);		} else {			self::debug('WebBrowser plugin not available...');		}	}	/**	 *	 * @param $url	 * @param $data	 * @param $callback	 * @param $param1	 * @param $param2	 * @param $param3	 * @return phpQueryObject	 */	public static function browserPost($url, $data, $callback, $param1 = null, $param2 = null, $param3 = null) {		if (self::plugin('WebBrowser')) {			$params = func_get_args();			return self::callbackRun(array(self::$plugins, 'browserPost'), $params);		} else {			self::debug('WebBrowser plugin not available...');		}	}	/**	 *	 * @param $ajaxSettings	 * @param $callback	 * @param $param1	 * @param $param2	 * @param $param3	 * @return phpQueryObject	 */	public static function browser($ajaxSettings, $callback, $param1 = null, $param2 = null, $param3 = null) {		if (self::plugin('WebBrowser')) {			$params = func_get_args();			return self::callbackRun(array(self::$plugins, 'browser'), $params);		} else {			self::debug('WebBrowser plugin not available...');		}	}	/**	 *	 * @param $code	 * @return string	 */	public static function php($code) {		return self::code('php', $code);	}	/**	 *	 * @param $type	 * @param $code	 * @return string	 */	public static function code($type, $code) {		return "<$type><!-- ".trim($code)." --></$type>";	}	public static function __callStatic($method, $params) {		return call_user_func_array(			array(phpQuery::$plugins, $method),			$params		);	}	protected static function dataSetupNode($node, $documentID) {		// search are return if alredy exists		foreach(phpQuery::$documents[$documentID]->dataNodes as $dataNode) {			if ($node->isSameNode($dataNode))				return $dataNode;		}		// if doesn't, add it		phpQuery::$documents[$documentID]->dataNodes[] = $node;		return $node;	}	protected static function dataRemoveNode($node, $documentID) {		// search are return if alredy exists		foreach(phpQuery::$documents[$documentID]->dataNodes as $k => $dataNode) {			if ($node->isSameNode($dataNode)) {				unset(self::$documents[$documentID]->dataNodes[$k]);				unset(self::$documents[$documentID]->data[ $dataNode->dataID ]);			}		}	}	public static function data($node, $name, $data, $documentID = null) {		if (! $documentID)			// TODO check if this works			$documentID = self::getDocumentID($node);		$document = phpQuery::$documents[$documentID];		$node = self::dataSetupNode($node, $documentID);		if (! isset($node->dataID))			$node->dataID = ++phpQuery::$documents[$documentID]->uuid;		$id = $node->dataID;		if (! isset($document->data[$id]))			$document->data[$id] = array();		if (! is_null($data))			$document->data[$id][$name] = $data;		if ($name) {			if (isset($document->data[$id][$name]))				return $document->data[$id][$name];		} else			return $id;	}	public static function removeData($node, $name, $documentID) {		if (! $documentID)			// TODO check if this works			$documentID = self::getDocumentID($node);		$document = phpQuery::$documents[$documentID];		$node = self::dataSetupNode($node, $documentID);		$id = $node->dataID;		if ($name) {			if (isset($document->data[$id][$name]))				unset($document->data[$id][$name]);			$name = null;			foreach($document->data[$id] as $name)				break;			if (! $name)				self::removeData($node, $name, $documentID);		} else {			self::dataRemoveNode($node, $documentID);		}	}}/** * Plugins static namespace class. * * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> * @package phpQuery * @todo move plugin methods here (as statics) */class phpQueryPlugins {	public function __call($method, $args) {		if (isset(phpQuery::$extendStaticMethods[$method])) {			$return = call_user_func_array(				phpQuery::$extendStaticMethods[$method],				$args			);		} else if (isset(phpQuery::$pluginsStaticMethods[$method])) {			$class = phpQuery::$pluginsStaticMethods[$method];			$realClass = "phpQueryPlugin_$class";			$return = call_user_func_array(				array($realClass, $method),				$args			);			return isset($return)				? $return				: $this;		} else			throw new Exception("Method '{$method}' doesnt exist");	}}/** * Shortcut to phpQuery::pq($arg1, $context) * Chainable. * * @see phpQuery::pq() * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery * @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> * @package phpQuery */function pq($arg1, $context = null) {	$args = func_get_args();	return call_user_func_array(		array('phpQuery', 'pq'),		$args	);}// add plugins dir and Zend framework to include pathset_include_path(	get_include_path()		.PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/'		.PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/plugins/');// why ? no __call nor __get for statics in php...// XXX __callStatic will be available in PHP 5.3phpQuery::$plugins = new phpQueryPlugins();// include bootstrap file (personal library config)if (file_exists(dirname(__FILE__).'/phpQuery/bootstrap.php'))	require_once dirname(__FILE__).'/phpQuery/bootstrap.php';
 |