diff --git a/QueryList.class.php b/QueryList.class.php index 3666f2d..3d7484f 100644 --- a/QueryList.class.php +++ b/QueryList.class.php @@ -7,13 +7,13 @@ * @author Jaeger * @email 734708094@qq.com * @link http://git.oschina.net/jae/QueryList - * @version 2.2.1 + * @version 3.0 * * @example * //获取CSDN移动开发栏目下的文章列表标题 $hj = QueryList::Query('http://mobile.csdn.net/',array("title"=>array('.unit h1','text'))); -print_r($hj->jsonArr); +print_r($hj->data); //回调函数1 function callfun1($content,$key) @@ -36,26 +36,29 @@ $reg = array( 'callback'=>array('HJ','callfun2') //调用回调函数2作为全局回调函数 ); $rang = '.left'; -$hj = QueryList::Query($url,$reg,$rang,'curl'); -print_r($hj->jsonArr); +$hj = QueryList::Query($url,$reg,$rang); +print_r($hj->data); //继续获取右边相关热门文章列表的标题以及链接地址 $hj->setQuery(array('title'=>array('','text'),'url'=>array('a','href')),'#con_two_2 li'); -//输出json数据 -echo $hj->getJson(); +//输出数据 +echo $hj->getData(); */ require 'phpQuery/phpQuery.php'; class QueryList { private $regArr; - public $jsonArr; + public $data; private $regRange; - private $html; - private $outputEncoding; + public $html; + private $pqHtml; + private $outputEncoding = false; + private $inputEncoding = false; private $htmlEncoding; - private static $ql; - private function __construct() { + public static $instances; + + public function __construct() { } /** * 静态方法,访问入口 @@ -67,72 +70,114 @@ class QueryList * 【回调函数】/【全局回调函数】:可选,字符串(函数名) 或 数组(array("类名","类的静态方法")),回调函数应有俩个参数,第一个参数是选择到的内容,第二个参数是选择器数组下标,回调函数会覆盖全局回调函数 * * @param string $regRange 【块选择器】:指 先按照规则 选出 几个大块 ,然后再分别再在块里面 进行相关的选择 - * @param string $getHtmlWay 【源码获取方式】指是通过curl抓取源码,还是通过file_get_contents抓取源码 * @param string $outputEncoding【输出编码格式】指要以什么编码输出(UTF-8,GB2312,.....),防止出现乱码,如果设置为 假值 则不改变原字符串编码 + * @param string $inputEncoding 【输入编码格式】明确指定输入的页面编码格式(UTF-8,GB2312,.....),防止出现乱码,如果设置为 假值 则自动识别 + * @param bool|false $removeHead 【是否移除页面头部区域】 乱码终极解决方案 + * @return mixed */ - public static function Query($page, $regArr, $regRange = '', $getHtmlWay = 'curl', $outputEncoding = false) + public static function Query($page,array $regArr, $regRange = '', $outputEncoding = null, $inputEncoding = null,$removeHead = false) { - if(!(self::$ql instanceof self)) - { - self::$ql = new self(); - } - self::$ql->_query($page, $regArr, $regRange, $getHtmlWay, $outputEncoding); - return self::$ql; + return self::getInstance()->_query($page, $regArr, $regRange, $outputEncoding, $inputEncoding,$removeHead); } + + /** + * 运行QueryList扩展 + * @param $class + * @param array $args + * @return mixed + * @throws QueryList_Exception + */ + public static function run($class,$args = array()) + { + $extension = self::getInstance($class); + return $extension->run($args); + } + + /** + * 获取任意实例 + * @return mixed + * @throws QueryList_Exception + */ + public static function getInstance() + { + $args = func_get_args(); + count($args) || $args = array(self::class); + $key = md5(serialize($args)); + $className = array_shift($args); + if(!class_exists($className)) { + throw new QueryList_Exception("no class {$className}"); + } + if(!isset(self::$instances[$key])) { + $rc = new ReflectionClass($className); + self::$instances[$key] = $rc->newInstanceArgs($args); + } + return self::$instances[$key]; + } + + /** + * 获取目标页面源码(主要用于调试) + * @param bool|true $rel + * @return string + */ + public function getHtml($rel = true) + { + return $rel?$this->qpHtml:$this->html; + } + + /** + * 获取采集结果数据 + * @param callback $callback + * @return array + */ + public function getData($callback = null) + { + if(is_callable($callback)){ + return array_map($callback,$this->data); + } + return $this->data; + } + /** * 重新设置选择器 - * @param array $regArr 选择器数组 - * @param string $regRange 块选择器 + * @param $regArr + * @param string $regRange + * @param string $outputEncoding + * @param string $inputEncoding + * @param bool|false $removeHead + * @return QueryList */ - public function setQuery($regArr, $regRange = '') + public function setQuery(array $regArr, $regRange = '',$outputEncoding = null, $inputEncoding = null,$removeHead = false) { - $this->jsonArr = array(); + return $this->_query($this->html,$regArr, $regRange, $outputEncoding, $inputEncoding,$removeHead); + } + + private function _query($page,array $regArr, $regRange, $outputEncoding, $inputEncoding,$removeHead) + { + $this->data = array(); + $this->html = $this->_isURL($page)?$this->_request($page):$page; + $outputEncoding && $this->outputEncoding = $outputEncoding; + $inputEncoding && $this->inputEncoding = $inputEncoding; + $removeHead && $this->html = $this->_removeHead($this->html); + $this->pqHtml = ''; + if(empty($this->html)){ + trigger_error("The received content is empty!",E_USER_NOTICE); + } + //获取编码格式 + $this->htmlEncoding = $this->inputEncoding?$this->inputEncoding:$this->_getEncode($this->html); + // $this->html = $this->_removeTags($this->html,array('script','style')); $this->regArr = $regArr; $this->regRange = $regRange; $this->_getList(); + return $this; } - /** - * 得到JSON结构的结果 - * @return string - */ - public function getJSON() - { - return json_encode($this->jsonArr); - } - private function _query($page, $regArr, $regRange, $getHtmlWay, $outputEncoding) - { - $this->jsonArr = array(); - $this->outputEncoding = $outputEncoding; - if ($this->_isURL($page)) { - if ($getHtmlWay == 'curl') { - //为了能获取https:// - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $page); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - $this->html = curl_exec($ch); - curl_close($ch); - } else { - $this->html = file_get_contents($page); - } - } else { - $this->html = $page; - } - //获取编码格式 - $this->htmlEncoding = $this->_getEncode($this->html); - // $this->html = $this->_removeTags($this->html,array('script','style')); - if (!empty($regArr)) { - $this->regArr = $regArr; - $this->regRange = $regRange; - $this->_getList(); - } - } + private function _getList() { - $hobj = phpQuery::newDocumentHTML($this->html); + $this->inputEncoding && phpQuery::$defaultCharset = $this->inputEncoding; + $document = phpQuery::newDocumentHTML($this->html); + $this->qpHtml = $document->htmlOuter(); if (!empty($this->regRange)) { - $robj = pq($hobj)->find($this->regRange); + $robj = pq($document)->find($this->regRange); $i = 0; foreach ($robj as $item) { while (list($key, $reg_value) = each($this->regArr)) { @@ -142,20 +187,20 @@ class QueryList switch ($reg_value[1]) { case 'text': - $this->jsonArr[$i][$key] = $this->_allowTags(pq($iobj)->html(),$tags); + $this->data[$i][$key] = $this->_allowTags(pq($iobj)->html(),$tags); break; case 'html': - $this->jsonArr[$i][$key] = $this->_stripTags(pq($iobj)->html(),$tags); + $this->data[$i][$key] = $this->_stripTags(pq($iobj)->html(),$tags); break; default: - $this->jsonArr[$i][$key] = pq($iobj)->attr($reg_value[1]); + $this->data[$i][$key] = pq($iobj)->attr($reg_value[1]); break; } if(isset($reg_value[3])){ - $this->jsonArr[$i][$key] = call_user_func($reg_value[3],$this->jsonArr[$i][$key],$key); + $this->data[$i][$key] = call_user_func($reg_value[3],$this->data[$i][$key],$key); }else if(isset($this->regArr['callback'])){ - $this->jsonArr[$i][$key] = call_user_func($this->regArr['callback'],$this->jsonArr[$i][$key],$key); + $this->data[$i][$key] = call_user_func($this->regArr['callback'],$this->data[$i][$key],$key); } } //重置数组指针 @@ -165,27 +210,27 @@ class QueryList } else { while (list($key, $reg_value) = each($this->regArr)) { if($key=='callback')continue; - $hobj = phpQuery::newDocumentHTML($this->html); + $document = phpQuery::newDocumentHTML($this->html); $tags = isset($reg_value[2])?$reg_value[2]:''; - $lobj = pq($hobj)->find($reg_value[0]); + $lobj = pq($document)->find($reg_value[0]); $i = 0; foreach ($lobj as $item) { switch ($reg_value[1]) { case 'text': - $this->jsonArr[$i][$key] = $this->_allowTags(pq($item)->html(),$tags); + $this->data[$i][$key] = $this->_allowTags(pq($item)->html(),$tags); break; case 'html': - $this->jsonArr[$i][$key] = $this->_stripTags(pq($item)->html(),$tags); + $this->data[$i][$key] = $this->_stripTags(pq($item)->html(),$tags); break; default: - $this->jsonArr[$i][$key] = pq($item)->attr($reg_value[1]); + $this->data[$i][$key] = pq($item)->attr($reg_value[1]); break; } if(isset($reg_value[3])){ - $this->jsonArr[$i][$key] = call_user_func($reg_value[3],$this->jsonArr[$i][$key],$key); + $this->data[$i][$key] = call_user_func($reg_value[3],$this->data[$i][$key],$key); }else if(isset($this->regArr['callback'])){ - $this->jsonArr[$i][$key] = call_user_func($this->regArr['callback'],$this->jsonArr[$i][$key],$key); + $this->data[$i][$key] = call_user_func($this->regArr['callback'],$this->data[$i][$key],$key); } $i++; @@ -194,10 +239,52 @@ class QueryList } if ($this->outputEncoding) { //编码转换 - $this->jsonArr = $this->_arrayConvertEncoding($this->jsonArr, $this->outputEncoding, $this->htmlEncoding); + $this->data = $this->_arrayConvertEncoding($this->data, $this->outputEncoding, $this->htmlEncoding); } phpQuery::$documents = array(); } + + /** + * URL请求 + * @param $url + * @return string + */ + private function _request($url) + { + if(function_exists('curl_init')){ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_AUTOREFERER, true); + curl_setopt($ch, CURLOPT_REFERER, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $result = curl_exec($ch); + curl_close($ch); + }elseif(version_compare(PHP_VERSION, '5.0.0')>=0){ + $opts = array( + 'http' => array( + 'header' => "Referer:{$url}" + ) + ); + $result = file_get_contents($url,false,stream_context_create($opts)); + }else{ + $result = file_get_contents($url); + } + return $result; + } + + /** + * 移除页面head区域代码 + * @param $html + * @return mixed + */ + private function _removeHead($html) + { + return preg_replace('/.+<\/head>/is','',$html); + } + /** * 获取文件编码 * @param $string @@ -207,6 +294,7 @@ class QueryList { return mb_detect_encoding($string, array('ASCII', 'GB2312', 'GBK', 'UTF-8')); } + /** * 转换数组值的编码格式 * @param array $arr @@ -219,6 +307,7 @@ class QueryList eval('$arr = '.iconv($fromEncoding, $toEncoding.'//IGNORE', var_export($arr,TRUE)).';'); return $arr; } + /** * 简单的判断一下参数是否为一个URL链接 * @param string $str @@ -231,6 +320,7 @@ class QueryList } return false; } + /** * 去除特定的html标签 * @param string $html @@ -248,6 +338,7 @@ class QueryList $html = preg_replace($p,"",trim($html)); return $html; } + /** * 保留特定的html标签 * @param string $html @@ -264,6 +355,7 @@ class QueryList } return strip_tags(trim($html),$allow); } + private function _tag($tags_str) { $tagArr = preg_split("/\s+/",$tags_str,-1,PREG_SPLIT_NO_EMPTY); @@ -279,6 +371,7 @@ class QueryList } return $tags; } + /** * 移除特定的html标签 * @param string $html @@ -293,7 +386,7 @@ class QueryList foreach ($tags as $tag) { $tag_str .= $tag_str?','.$tag:$tag; } - phpQuery::$defaultCharset = $this->htmlEncoding; + phpQuery::$defaultCharset = $this->inputEncoding?$this->inputEncoding:$this->htmlEncoding; $doc = phpQuery::newDocumentHTML($html); pq($doc)->find($tag_str)->remove(); $html = pq($doc)->htmlOuter(); @@ -303,5 +396,27 @@ class QueryList } } +class QueryList_Exception extends Exception{ +} + +class Autoload +{ + public static function load($className) + { + $files = array( + sprintf('%s/extensions/%s.php',__DIR__,$className), + sprintf('%s/extensions/vendors/%s.php',__DIR__,$className) + ); + foreach ($files as $file) { + if(is_file($file)){ + require $file; + return true; + } + } + return false; + } +} + +spl_autoload_register(array('Autoload','load')); diff --git a/demo/Searcher.class.php b/demo/Searcher.class.php deleted file mode 100644 index 42ef808..0000000 --- a/demo/Searcher.class.php +++ /dev/null @@ -1,152 +0,0 @@ -jsonArr); - - $json = Searcher::S('QueryList交流')->getJSON(); - print_r($json); - */ -require '../QueryList.class.php'; - class Searcher - { - private $searcher; - private $key; - private $num; - private $page; - private $regArr ; - private $regRange ; - private $regZnum; - public $jsonArr; - private static $s; - - public static function S($key,$searcher = 'baidu',$num = 10,$page = 1) - { - if(!(self::$s instanceof self)) - { - self::$s = new self(); - } - self::$s->query($key,$searcher,$num,$page); - return self::$s; - } - private function query($key,$searcher,$num,$page) - { - if($searcher=='baidu') - { - $this->regArr = array("title"=>array("h3.t a,#ting_singlesong_box a","text"),"tCon"=>array("div.c-abstract,font:slice(0,2),div#weibo,table tr:eq(0),div.c-abstract-size p:eq(0),div.vd_sitcom_new_tinfo","text"),"url"=>array("h3.t a,#ting_singlesong_box a","href"),"host"=>array("div.f13>span.g","text")); - $this->regRange = '.result,.result-op'; - $this->regZnum=array("zNum"=>array("span.nums","text")); - } - else if($searcher=='google') - { - $this->regArr = array("title"=>array("h3.r a","text"),"tCon"=>array("span.st","text"),"url"=>array("h3.r a","href")); - $this->regRange = 'li.g'; - $this->regZnum=array("zNum"=>array("div#resultStats","text")); - } - else if($searcher=='sogou') - { - $this->regArr = array("title"=>array("h3 a","text"),"tCon"=>array("div.ft","text"),"url"=>array("h3 a","href")); - $this->regRange = '[id^=rb_]'; - $this->regZnum=array("zNum"=>array("div.mun","text")); - } - $this->searcher = $searcher; - $this->key = $key; - $this->num = $num; - $this->page = $page-1; - $this->getList(); - } - private function getList() - { - $s = urlencode($this->key); - $num = $this->num; - $getHtmlWay = 'get'; - $start = $this->num*$this->page; - if($this->searcher=='baidu') - { - $url = "http://www.baidu.com/s?pn=$start&rn=$num&wd=$s"; - $reg_znum='/[\d,]+/'; - } - else if($this->searcher=='google') - { - $url="https://www.google.com.hk/search?filter=0&lr=&newwindow=1&safe=images&hl=en&as_qdr=all&num=$num&start=$start&q=$s"; - $reg_znum='/([\d,]+) result(s)?/'; - $getHtmlWay = 'curl'; - } - else if($this->searcher=='sogou') - { - $url="http://www.sogou.com/web?query=$s&num=$num&page=".$this->page; - $reg_znum='/[\d,]+/'; - } - $searcherObj = QueryList::Query($url,$this->regArr,$this->regRange,$getHtmlWay,false); - for($i=0;$ijsonArr);$i++) - { - if($this->searcher=='baidu') - { - // $searcherObj->jsonArr[$i]['url'] = $this->getBaiduRealURL($searcherObj->jsonArr[$i]['url']); - } - else if($this->searcher=='google') - { - $searcherObj->jsonArr[$i]['url'] = $this->getGoogleRealURL($searcherObj->jsonArr[$i]['url']); - } - } - $this->jsonArr = $searcherObj->jsonArr ; - - //获取总共结果条数 - - $searcherObj->setQuery($this->regZnum); - $zNum = $searcherObj->jsonArr[0]['zNum']; - preg_match($reg_znum,$zNum,$arr)?$zNum=$arr[0]:$zNum=0; - $zNum = (int)str_replace(',','',$zNum); - //计算总页数 - $zPage = ceil($zNum/$this->num); - $this->jsonArr=array('num'=>$this->num,'page'=>((int)$this->page+1),'zNum'=>$zNum,'zPage'=>$zPage,"s"=>"$this->key",'other'=>array('author'=>'JAE','QQ'=>'734708094','blog'=>'http://blog.jaekj.com'),'data'=>$this->jsonArr); - - - } - public function getJSON() - { - return json_encode($this->jsonArr); - } - private function getBaiduRealURL($url) - { - //得到百度跳转的真正地址 - $header = get_headers($url,1); - if (strpos($header[0],'301') || strpos($header[0],'302')) - { - if(is_array($header['Location'])) - { - //return $header['Location'][count($header['Location'])-1]; - return $header['Location'][0]; - } - else - { - return $header['Location']; - } - } - else - { - return $url; - } - } - private function getGoogleRealURL($url) - { - $reg_url = '/q=(.+)&/U'; - return preg_match($reg_url,$url,$arr)?urldecode($arr[1]):$url; - - } - } - - - - $hj = Searcher::S('site:pan.baidu.com torrent','sogou',20,2); - print_r( $hj->jsonArr); \ No newline at end of file diff --git a/demo/demo.php b/demo/demo.php deleted file mode 100644 index dc4c7c6..0000000 --- a/demo/demo.php +++ /dev/null @@ -1,68 +0,0 @@ -array(".code_title a:eq(0)","text"),"url"=>array(".code_title a:eq(0)","href"),"author"=>array("img","title")); -$rang = ".code_list li"; -//使用curl抓取源码并以GBK编码格式输出 -$hj = QueryList::Query($url,$reg,$rang,'curl','GBK'); -$arr = $hj->jsonArr; -echo "
";
-print_r($arr);
-echo "

"; - -echo '上面的是GBK格式输出的,而页面是UTF-8格式的,所以会看到输出是乱码!'; -echo '
'; - -//如果还想采当前页面右边的 TOP40活跃贡献者 图像,得到JSON数据,可以这样写 -$reg = array("portrait"=>array(".hot_top img","src")); -$hj->setQuery($reg); -$json = $hj->getJSON(); -echo $json . "
"; - -//采OSC内容页内容 -$url = "http://www.oschina.net/code/snippet_186288_23816"; -$reg = array("title"=>array(".QTitle h1","text"),"con"=>array(".Content","html")); -$hj = QueryList::Query($url,$reg); -$arr = $hj->jsonArr; -echo "
";
-print_r($arr);
-echo "

"; - -//抓取网站基本信息 -//设置规则 -$reg = array( - //抓取网站keywords - "kw" => array("meta[name=keywords]","content"), - //抓取网站描述 - "desc" => array("meta[name=description]","content"), - //抓取网站标题 - "title" => array("title","text"), - //抓取网站第一个css link的链接 - "css1" => array("link:eq(0)","href"), - //抓取网站第二个js link的链接 - "js2" => array("script[src]:eq(1)","src") - ); -//抓取的目标站 -$url = 'http://x.44i.cc/'; -//抓取 -$data = QueryList::Query($url,$reg)->jsonArr; -print_r($data); - -//下面单独演示回调函数的用法 -//抓取网站keywords并分离每个关键词 -$reg = array( - //抓取网站keywords,并调用自定义函数fun - "kw" => array("meta[name=keywords]","content",'','fun') - ); -//自定义回调函数 -function fun($content,$key){ - //分离关键词 - return explode(',', $content); -} -//抓取的目标站 -$url = 'http://x.44i.cc/'; -//抓取 -$data = QueryList::Query($url,$reg)->jsonArr; -print_r($data); \ No newline at end of file diff --git a/demo/thanks.png b/demo/thanks.png deleted file mode 100644 index b5c72a7..0000000 Binary files a/demo/thanks.png and /dev/null differ diff --git a/demo/一个完整的DEMO项目.zip b/demo/一个完整的DEMO项目.zip deleted file mode 100644 index 74d997e..0000000 Binary files a/demo/一个完整的DEMO项目.zip and /dev/null differ diff --git a/extensions/AQuery.php b/extensions/AQuery.php new file mode 100644 index 0000000..cbb936b --- /dev/null +++ b/extensions/AQuery.php @@ -0,0 +1,19 @@ + + * @Date: 2015-11-11 17:52:40 + * @Last Modified by: Jaeger + * @Last Modified time: 2015-11-16 09:57:56 + * @version 1.0 + * 扩展基类 + */ +abstract class AQuery +{ + abstract function run(array $args); + + public function getInstance($className = 'QueryList', $params = null) + { + return QueryList::getInstance($className,$params); + } + +} \ No newline at end of file diff --git a/extensions/Login.php b/extensions/Login.php new file mode 100644 index 0000000..93c059e --- /dev/null +++ b/extensions/Login.php @@ -0,0 +1,44 @@ + + * @Date: 2015-11-11 17:52:40 + * @Last Modified by: Jaeger + * @Last Modified time: 2015-11-16 09:57:58 + * @version 1.0 + * 模拟登陆扩展 + */ +class Login extends Request +{ + private $http; + public $html; + + public function run(array $args) + { + $this->http = $this->hq($args); + $this->html = $this->http->result; + return $this; + } + + public function get($url,$callback = null,$args = null) + { + $result = $this->http->get($url); + return $this->getQL($result,$callback,$args); + } + + public function post($url,$data=array(),$callback = null,$args = null) + { + $result = $this->http->post($url,$data); + return $this->getQL($result,$callback,$args); + } + + private function getQL($html,$callback = null,$args = null) + { + if(is_callable($callback)){ + $result = call_user_func($callback,$result,$args); + } + $ql = $this->getInstance(); + $ql->html = $html; + return $ql; + } + +} \ No newline at end of file diff --git a/extensions/Multi.php b/extensions/Multi.php new file mode 100644 index 0000000..2466421 --- /dev/null +++ b/extensions/Multi.php @@ -0,0 +1,73 @@ + + * @Date: 2015-11-11 17:52:40 + * @Last Modified by: Jaeger + * @Last Modified time: 2015-11-16 09:57:14 + * @version 1.0 + * 多线程扩展 + */ +class Multi extends AQuery +{ + private $curl; + private $args; + + public function run(array $args) + { + $default = array( + 'curl' => array( + 'opt' => array( + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSL_VERIFYHOST => false, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_AUTOREFERER => true, + ), + 'maxThread' => 100, + 'maxTry' => 3 + ), + 'list' => array(), + 'success' => function(){}, + 'error' => function(){}, + 'start' => true + ); + + $this->args = array_merge($default,$args); + + $this->curl = $this->getInstance('CurlMulti'); + if(isset($this->args['curl'])){ + foreach ($this->args['curl'] as $k => $v) { + $this->curl->$k = $v; + } + } + $this->add($this->args['list']); + + return $this->args['start']?$this->start():$this; + } + + public function add($urls,$success = false,$error = false) + { + if(!is_array($urls)){ + $urls = array($urls); + } + foreach ($urls as $url) { + $this->curl->add( + array( + 'url' => $url, + 'args' => $this, + 'opt' => array( + CURLOPT_REFERER => $url + ) + ), + $success?$success:$this->args['success'], + $error?$error:$this->args['error'] + ); + } + return $this; + } + + public function start() + { + $this->curl->start(); + return $this; + } +} \ No newline at end of file diff --git a/extensions/Request.php b/extensions/Request.php new file mode 100644 index 0000000..423b099 --- /dev/null +++ b/extensions/Request.php @@ -0,0 +1,37 @@ + + * @Date: 2015-07-15 23:27:52 + * @Last Modified by: Jaeger + * @Last Modified time: 2015-11-16 11:01:19 + * @version 1.0 + * 网络操作扩展 + */ + +class Request extends AQuery +{ + + protected function hq(array $args) + { + $args = array( + 'http' => isset($args['http'])?$args['http']:$args, + 'callback' => isset($args['callback'])?$args['callback']:'', + 'args' => isset($args['args'])?$args['args']:'' + ); + $http = $this->getInstance('Http'); + $http->initialize($args['http']); + $http->execute(); + if(!empty($args['callback'])){ + $http->result = call_user_func($args['callback'],$http->result,$args['args']); + } + return $http; + } + + public function run(array $args) + { + $http = $this->hq($args); + $ql = $this->getInstance(); + $ql->html = $http->result; + return $ql; + } +} \ No newline at end of file diff --git a/extensions/vendors/CurlMulti.php b/extensions/vendors/CurlMulti.php new file mode 100644 index 0000000..ab75a3d --- /dev/null +++ b/extensions/vendors/CurlMulti.php @@ -0,0 +1,698 @@ +maxThreadNoType is maxThread-sum(maxThreadType).If less than 0 $this->maxThreadNoType is set to 0. + public $maxThreadType = array (); + // retry time(s) when task failed + public $maxTry = 3; + // operation, class level curl opt + public $opt = array (); + // cache options,dirLevel values is less than 3 + public $cache = array ( + 'enable' => false, + 'enableDownload' => false, + 'compress' => false, + 'dir' => null, + 'expire' => 86400, + 'dirLevel' => 1 + ); + // stack or queue + public $taskPoolType = 'stack'; + // eliminate duplicate for taskpool, will delete previous task and add new one + public $taskOverride = false; + // task callback,add() should be called in callback, $cbTask[0] is callback, $cbTask[1] is param. + public $cbTask = null; + // status callback + public $cbInfo = null; + // user callback + public $cbUser = null; + // common fail callback, called if no one specified + public $cbFail = null; + + // is the loop running + protected $isRunning = false; + // max thread num no type + protected $maxThreadNoType = null; + // all added task was saved here first + protected $taskPool = array (); + // taskPool with high priority + protected $taskPoolAhead = array (); + // running task(s) + protected $taskRunning = array (); + // failed task need to retry + protected $taskFail = array (); + + // handle of multi-thread curl + private $mh = null; + // user error + private $userError = null; + // if __construct called + private $isConstructCalled = false; + // running info + private $info = array ( + 'all' => array ( + // process start time + 'startTime' => null, + // download start time + 'startTimeDownload' => null, + // the real multi-thread num + 'activeNum' => null, + // finished task in the queue + 'queueNum' => null, + // byte + 'downloadSize' => 0, + // finished task number,include failed task and cache + 'finishNum' => 0, + // The number of cache used + 'cacheNum' => 0, + // completely failed task number + 'failNum' => 0, + // task num has added + 'taskNum' => 0, + // task running num by type, + 'taskRunningNumType' => array (), + // task ruuning num no type + 'taskRunningNumNoType' => 0, + // $this->taskPool size + 'taskPoolNum' => 0, + // $this->taskRunning size + 'taskRunningNum' => 0, + // $this->taskFail size + 'taskFailNum' => 0, + // finish percent + 'finishPercent' => 0, + // time cost + 'timeSpent' => 0, + // download time cost + 'timeSpentDownload' => 0, + // curl task speed + 'taskSpeedNoCache' => 0, + // network speed, bytes + 'downloadSpeed' => 0 + ), + 'running' => array () + ); + function __construct() { + $this->isConstructCalled = true; + if (version_compare ( PHP_VERSION, '5.1.0' ) < 0) { + throw new CurlMulti_Exception ( 'PHP 5.1.0+ is needed' ); + } + } + + /** + * add a task to taskPool + * + * @param array $item + * array('url'=>'',['file'=>'',['opt'=>array(),['args'=>array(),['ctl'=>array('type'=>'','ahead'=>false,'cache'=>array('enable'=>bool,'expire'=>0),'close'=>true))]]]]) + * @param mixed $process + * success callback,for callback first param array('info'=>,'content'=>), second param $item[args] + * @param mixed $fail + * curl fail callback,for callback first param array('error'=>array(0=>code,1=>msg),'info'=>array),second param $item[args]; + * @throws CurlMulti_Exception + * @return \frame\lib\CurlMulti + */ + function add(array $item, $process = null, $fail = null) { + // check + if (! is_array ( $item )) { + user_error ( 'item must be array, item is ' . gettype ( $item ), E_USER_WARNING ); + } else { + $item ['url'] = trim ( $item ['url'] ); + if (empty ( $item ['url'] )) { + user_error ( "url can't be empty, url=$item[url]", E_USER_WARNING ); + } else { + // replace space with + to avoid some curl problems + $item ['url'] = str_replace ( ' ', '+', $item ['url'] ); + // fix + if (empty ( $item ['file'] )) + $item ['file'] = null; + if (empty ( $item ['opt'] )) + $item ['opt'] = array (); + if (empty ( $item ['args'] )) + $item ['args'] = array (); + if (empty ( $item ['ctl'] )) { + $item ['ctl'] = array (); + } + if (! isset ( $item ['ctl'] ['cache'] ) || ! isset ( $item ['ctl'] ['cache'] ['enable'] )) { + $item ['ctl'] ['cache'] = array ( + 'enable' => false, + 'expire' => 0 + ); + } + if (! isset ( $item ['ctl'] ['ahead'] )) { + $item ['ctl'] ['ahead'] = false; + } + if (empty ( $process )) { + $process = null; + } + if (empty ( $fail )) { + $fail = null; + } + $task = array (); + $task [self::TASK_ITEM_URL] = $item ['url']; + $task [self::TASK_ITEM_FILE] = $item ['file']; + $task [self::TASK_ITEM_ARGS] = array ( + $item ['args'] + ); + $task [self::TASK_ITEM_OPT] = $item ['opt']; + $task [self::TASK_ITEM_CTL] = $item ['ctl']; + $task [self::TASK_PROCESS] = $process; + $task [self::TASK_FAIL] = $fail; + $task [self::TASK_TRYED] = 0; + $task [self::TASK_CH] = null; + $this->addTaskPool ( $task ); + $this->info ['all'] ['taskNum'] ++; + } + } + return $this; + } + + /** + * add task to taskPool + * + * @param unknown $task + */ + private function addTaskPool($task) { + // uniq + if ($this->taskOverride) { + foreach ( array ( + 'taskPoolAhead', + 'taskPool' + ) as $v ) { + foreach ( $this->$v as $k1 => $v1 ) { + if ($v1 [self::TASK_ITEM_URL] == $task [self::TASK_ITEM_URL]) { + $t = &$this->$v; + unset ( $t [$k1] ); + } + } + } + } + // add + if (true == $task [self::TASK_ITEM_CTL] ['ahead']) { + $this->taskPoolAhead [] = $task; + } else { + if ($this->taskPoolType == 'queue') { + $this->taskPool [] = $task; + } elseif ($this->taskPoolType == 'stack') { + array_unshift ( $this->taskPool, $task ); + } else { + throw new CurlMulti_Exception ( 'taskPoolType not found, taskPoolType=' . $this->taskPoolType ); + } + } + } + + /** + * Perform the actual task(s). + */ + function start() { + if ($this->isRunning) { + throw new CurlMulti_Exception ( __CLASS__ . ' is running !' ); + } + if (false === $this->isConstructCalled) { + throw new CurlMulti_Exception ( __CLASS__ . ' __construct is not called' ); + } + $this->mh = curl_multi_init (); + $this->info ['all'] ['startTime'] = time (); + $this->info ['all'] ['timeStartDownload'] = null; + $this->info ['all'] ['downloadSize'] = 0; + $this->info ['all'] ['finishNum'] = 0; + $this->info ['all'] ['cacheNum'] = 0; + $this->info ['all'] ['failNum'] = 0; + $this->info ['all'] ['taskNum'] = 0; + $this->info ['all'] ['taskRunningNumNoType'] = 0; + $this->setThreadData (); + $this->isRunning = true; + $this->addTask (); + do { + $this->exec (); + curl_multi_select ( $this->mh ); + $this->callCbInfo (); + if (isset ( $this->cbUser )) { + call_user_func ( $this->cbUser ); + } + while ( false != ($curlInfo = curl_multi_info_read ( $this->mh, $this->info ['all'] ['queueNum'] )) ) { + $ch = $curlInfo ['handle']; + $task = $this->taskRunning [( int ) $ch]; + $info = curl_getinfo ( $ch ); + $this->info ['all'] ['downloadSize'] += $info ['size_download']; + if (isset ( $task [self::TASK_FP] )) { + fclose ( $task [self::TASK_FP] ); + } + if ($curlInfo ['result'] == CURLE_OK) { + $param = array (); + $param ['info'] = $info; + $param ['ext'] = array ( + 'ch' => $ch + ); + if (! isset ( $task [self::TASK_ITEM_FILE] )) { + $param ['content'] = curl_multi_getcontent ( $ch ); + } + } + curl_multi_remove_handle ( $this->mh, $ch ); + // must close first,other wise download may be not commpleted in process callback + if (! array_key_exists ( 'close', $task [self::TASK_ITEM_CTL] ) || $task [self::TASK_ITEM_CTL] ['close'] == true) { + curl_close ( $ch ); + } + if ($curlInfo ['result'] == CURLE_OK) { + $this->process ( $task, $param, false ); + } + // error handle + $callFail = false; + if ($curlInfo ['result'] !== CURLE_OK || isset ( $this->userError )) { + if ($task [self::TASK_TRYED] >= $this->maxTry) { + // user error + if (isset ( $this->userError )) { + $err = array ( + 'error' => $this->userError + ); + } else { + $err = array ( + 'error' => array ( + $curlInfo ['result'], + curl_error ( $ch ) + ) + ); + } + $err ['info'] = $info; + if (isset ( $task [self::TASK_FAIL] ) || isset ( $this->cbFail )) { + array_unshift ( $task [self::TASK_ITEM_ARGS], $err ); + $callFail = true; + } else { + echo "\nError " . implode ( ', ', $err ['error'] ) . ", url=$info[url]\n"; + } + $this->info ['all'] ['failNum'] ++; + } else { + $task [self::TASK_TRYED] ++; + $task [self::TASK_ITEM_CTL] ['useCache'] = false; + $this->taskFail [] = $task; + $this->info ['all'] ['taskNum'] ++; + } + if (isset ( $this->userError )) { + unset ( $this->userError ); + } + } + if ($callFail) { + if (isset ( $task [self::TASK_FAIL] )) { + call_user_func_array ( $task [self::TASK_FAIL], $task [self::TASK_ITEM_ARGS] ); + } elseif (isset ( $this->cbFail )) { + call_user_func_array ( $this->cbFail, $task [self::TASK_ITEM_ARGS] ); + } + } + unset ( $this->taskRunning [( int ) $ch] ); + if (array_key_exists ( 'type', $task [self::TASK_ITEM_CTL] )) { + $this->info ['all'] ['taskRunningNumType'] [$task [self::TASK_ITEM_CTL] ['type']] --; + } else { + $this->info ['all'] ['taskRunningNumNoType'] --; + } + $this->addTask (); + $this->info ['all'] ['finishNum'] ++; + // if $this->info['all']['queueNum'] grow very fast there will be no efficiency lost,because outer $this->exec() won't be executed. + $this->exec (); + $this->callCbInfo (); + if (isset ( $this->cbUser )) { + call_user_func ( $this->cbUser ); + } + } + } while ( $this->info ['all'] ['activeNum'] || $this->info ['all'] ['queueNum'] || ! empty ( $this->taskFail ) || ! empty ( $this->taskRunning ) || ! empty ( $this->taskPool ) ); + $this->callCbInfo ( true ); + curl_multi_close ( $this->mh ); + unset ( $this->mh ); + $this->isRunning = false; + } + + /** + * call $this->cbInfo + */ + private function callCbInfo($force = false) { + static $lastTime; + if (! isset ( $lastTime )) { + $lastTime = time (); + } + $now = time (); + if (($force || $now - $lastTime > 0) && isset ( $this->cbInfo )) { + $lastTime = $now; + $this->info ['all'] ['taskPoolNum'] = count ( $this->taskPool ); + $this->info ['all'] ['taskRunningNum'] = count ( $this->taskRunning ); + $this->info ['all'] ['taskFailNum'] = count ( $this->taskFail ); + if ($this->info ['all'] ['taskNum'] > 0) { + $this->info ['all'] ['finishPercent'] = round ( $this->info ['all'] ['finishNum'] / $this->info ['all'] ['taskNum'], 4 ); + } + $this->info ['all'] ['timeSpent'] = time () - $this->info ['all'] ['startTime']; + if (isset ( $this->info ['all'] ['timeStartDownload'] )) { + $this->info ['all'] ['timeSpentDownload'] = time () - $this->info ['all'] ['timeStartDownload']; + } + if ($this->info ['all'] ['timeSpentDownload'] > 0) { + $this->info ['all'] ['taskSpeedNoCache'] = round ( ($this->info ['all'] ['finishNum'] - $this->info ['all'] ['cacheNum']) / $this->info ['all'] ['timeSpentDownload'], 2 ); + $this->info ['all'] ['downloadSpeed'] = round ( $this->info ['all'] ['downloadSize'] / $this->info ['all'] ['timeSpentDownload'], 2 ); + } + // running + $this->info ['running'] = array (); + foreach ( $this->taskRunning as $k => $v ) { + $this->info ['running'] [$k] = curl_getinfo ( $v [self::TASK_CH] ); + } + call_user_func_array ( $this->cbInfo, array ( + $this->info + ) ); + } + } + + /** + * set $this->maxThreadNoType, $this->info['all']['taskRunningNumType'], $this->info['all']['taskRunningNumNoType'] etc + */ + private function setThreadData() { + $this->maxThreadNoType = $this->maxThread - array_sum ( $this->maxThreadType ); + if ($this->maxThreadNoType < 0) { + $this->maxThreadNoType = 0; + } + // unset none exitst type num + foreach ( $this->info ['all'] ['taskRunningNumType'] as $k => $v ) { + if ($v == 0 && ! array_key_exists ( $k, $this->maxThreadType )) { + unset ( $this->info ['all'] ['taskRunningNumType'] [$k] ); + } + } + // init type num + foreach ( $this->maxThreadType as $k => $v ) { + if ($v == 0) { + user_error ( 'maxThreadType[' . $k . '] is 0, task of this type will never be added!', E_USER_WARNING ); + } + if (! array_key_exists ( $k, $this->info ['all'] ['taskRunningNumType'] )) { + $this->info ['all'] ['taskRunningNumType'] [$k] = 0; + } + } + } + + /** + * curl_multi_exec() + */ + private function exec() { + while ( curl_multi_exec ( $this->mh, $this->info ['all'] ['activeNum'] ) === CURLM_CALL_MULTI_PERFORM ) { + } + } + + /** + * add a task to curl, keep $this->maxThread concurrent automatically + */ + private function addTask() { + $c = $this->maxThread - count ( $this->taskRunning ); + while ( $c > 0 ) { + $task = array (); + // search failed first + if (! empty ( $this->taskFail )) { + $task = array_pop ( $this->taskFail ); + } else { + // cbTask + if (0 < ($this->maxThread - count ( $this->taskPool )) and ! empty ( $this->cbTask )) { + if (! isset ( $this->cbTask [1] )) { + $this->cbTask [1] = array (); + } + call_user_func_array ( $this->cbTask [0], array ( + $this->cbTask [1] + ) ); + } + if (! empty ( $this->taskPoolAhead )) { + $task = array_pop ( $this->taskPoolAhead ); + } elseif (! empty ( $this->taskPool )) { + if ($this->taskPoolType == 'stack') { + $task = array_pop ( $this->taskPool ); + } elseif ($this->taskPoolType == 'queue') { + $task = array_shift ( $this->taskPool ); + } else { + throw new CurlMulti_Exception ( 'taskPoolType not found, taskPoolType=' . $this->taskPoolType ); + } + } + } + $noAdd = false; + $cache = null; + if (! empty ( $task )) { + if (true == $task [self::TASK_ITEM_CTL] ['cache'] ['enable'] || $this->cache ['enable']) { + $cache = $this->cache ( $task ); + if (null !== $cache) { + if (isset ( $task [self::TASK_ITEM_FILE] )) { + file_put_contents ( $task [self::TASK_ITEM_FILE], $cache ['content'], LOCK_EX ); + unset ( $cache ['content'] ); + } + $this->process ( $task, $cache, true ); + $this->info ['all'] ['cacheNum'] ++; + $this->info ['all'] ['finishNum'] ++; + $this->callCbInfo (); + } + } + if (! $cache) { + $this->setThreadData (); + if (array_key_exists ( 'type', $task [self::TASK_ITEM_CTL] ) && ! array_key_exists ( $task [self::TASK_ITEM_CTL] ['type'], $this->maxThreadType )) { + user_error ( 'task was set to notype because type was not set in $this->maxThreadType, type=' . $task [self::TASK_ITEM_CTL] ['type'], E_USER_WARNING ); + unset ( $task [self::TASK_ITEM_CTL] ['type'] ); + } + if (array_key_exists ( 'type', $task [self::TASK_ITEM_CTL] )) { + $maxThread = $this->maxThreadType [$task [self::TASK_ITEM_CTL] ['type']]; + $isNoType = false; + } else { + $maxThread = $this->maxThreadNoType; + $isNoType = true; + } + if ($isNoType && $maxThread == 0) { + user_error ( 'task was disgarded because maxThreadNoType=0, url=' . $task [self::TASK_ITEM_URL], E_USER_WARNING ); + } + if (($isNoType && $this->info ['all'] ['taskRunningNumNoType'] < $maxThread) || (! $isNoType && $this->info ['all'] ['taskRunningNumType'] [$task [self::TASK_ITEM_CTL] ['type']] < $maxThread)) { + $task [self::TASK_CH] = $this->curlInit ( $task [self::TASK_ITEM_URL] ); + // is a download task? + if (isset ( $task [self::TASK_ITEM_FILE] )) { + // curl can create the last level directory + $dir = dirname ( $task [self::TASK_ITEM_FILE] ); + if (! file_exists ( $dir )) + mkdir ( $dir, 0777 ); + $task [self::TASK_FP] = fopen ( $task [self::TASK_ITEM_FILE], 'w' ); + curl_setopt ( $task [self::TASK_CH], CURLOPT_FILE, $task [self::TASK_FP] ); + } + // single task curl option + if (isset ( $task [self::TASK_ITEM_OPT] )) { + foreach ( $task [self::TASK_ITEM_OPT] as $k => $v ) { + curl_setopt ( $task [self::TASK_CH], $k, $v ); + } + } + $this->taskRunning [( int ) $task [self::TASK_CH]] = $task; + if (! isset ( $this->info ['all'] ['timeStartDownload'] )) { + $this->info ['all'] ['timeStartDownload'] = time (); + } + if ($isNoType) { + $this->info ['all'] ['taskRunningNumNoType'] ++; + } else { + $this->info ['all'] ['taskRunningNumType'] [$task [self::TASK_ITEM_CTL] ['type']] ++; + } + curl_multi_add_handle ( $this->mh, $task [self::TASK_CH] ); + } else { + // rotate task to pool + if ($task [self::TASK_TRYED] > 0) { + array_unshift ( $this->taskFail, $task ); + } else { + array_unshift ( $this->taskPool, $task ); + } + $noAdd = true; + } + } + } + if (! $cache || $noAdd) { + $c --; + } + } + } + + /** + * do process + * + * @param unknown $task + * @param unknown $r + * @param unknown $isCache + */ + private function process($task, $r, $isCache) { + array_unshift ( $task [self::TASK_ITEM_ARGS], $r ); + if (isset ( $task [self::TASK_PROCESS] )) { + $userRes = call_user_func_array ( $task [self::TASK_PROCESS], $task [self::TASK_ITEM_ARGS] ); + } + if (! isset ( $userRes )) { + $userRes = true; + } + array_shift ( $task [self::TASK_ITEM_ARGS] ); + // backoff + if (false === $userRes) { + if (false == $this->cache ['enable'] && false == $task [self::TASK_ITEM_CTL] ['cache'] ['enable']) { + $task [self::TASK_ITEM_CTL] ['cache'] = array ( + 'enable' => true, + 'expire' => 3600 + ); + } + $this->addTaskPool ( $task ); + } + // write cache + if (false == $isCache && false == isset ( $this->userError ) && (true == $task [self::TASK_ITEM_CTL] ['cache'] ['enable']) || $this->cache ['enable']) { + $this->cache ( $task, $r ); + } + } + + /** + * set or get file cache + * + * @param string $url + * @param mixed $content + * array('info','content') + * @return return array|null|boolean + */ + private function cache($task, $content = null) { + if (! isset ( $this->cache ['dir'] )) + throw new CurlMulti_Exception ( 'Cache dir is not defined' ); + $url = $task [self::TASK_ITEM_URL]; + $key = md5 ( $url ); + $isDownload = isset ( $task [self::TASK_ITEM_FILE] ); + $file = rtrim ( $this->cache ['dir'], '/' ) . '/'; + if (isset ( $this->cache ['dirLevel'] ) && $this->cache ['dirLevel'] != 0) { + if ($this->cache ['dirLevel'] == 1) { + $file .= substr ( $key, 0, 3 ) . '/' . substr ( $key, 3 ); + } elseif ($this->cache ['dirLevel'] == 2) { + $file .= substr ( $key, 0, 3 ) . '/' . substr ( $key, 3, 3 ) . '/' . substr ( $key, 6 ); + } else { + throw new CurlMulti_Exception ( 'cache dirLevel is invalid, dirLevel=' . $this->cache ['dirLevel'] ); + } + } else { + $file .= $key; + } + $r = null; + if (! isset ( $content )) { + if (file_exists ( $file )) { + if (true == $task [self::TASK_ITEM_CTL] ['cache'] ['enable']) { + $expire = $task [self::TASK_ITEM_CTL] ['cache'] ['expire']; + } else { + $expire = $this->cache ['expire']; + } + if (time () - filemtime ( $file ) < $expire) { + $r = file_get_contents ( $file ); + if ($this->cache ['compress']) { + $r = gzuncompress ( $r ); + } + $r = unserialize ( $r ); + if ($isDownload) { + $r ['content'] = base64_decode ( $r ['content'] ); + } + } + } + } else { + $r = false; + // check main cache directory + if (! is_dir ( $this->cache ['dir'] )) { + throw new CurlMulti_Exception ( "Cache dir doesn't exists" ); + } else { + $dir = dirname ( $file ); + // level 1 subdir + if (isset ( $this->cache ['dirLevel'] ) && $this->cache ['dirLevel'] > 1) { + $dir1 = dirname ( $dir ); + if (! is_dir ( $dir1 ) && ! mkdir ( $dir1 )) { + throw new CurlMulti_Exception ( 'Create dir failed, dir=' . $dir1 ); + } + } + if (! is_dir ( $dir ) && ! mkdir ( $dir )) { + throw new CurlMulti_Exception ( 'Create dir failed, dir=' . $dir ); + } + if ($isDownload) { + $content ['content'] = base64_encode ( file_get_contents ( $task [self::TASK_ITEM_FILE] ) ); + } + $content = serialize ( $content ); + if ($this->cache ['compress']) { + $content = gzcompress ( $content ); + } + if (file_put_contents ( $file, $content, LOCK_EX )) { + $r = true; + } else { + throw new CurlMulti_Exception ( 'Write cache file failed' ); + } + } + } + return $r; + } + + /** + * user error for current callback + * not curl error + * must be called in process callback + * + * @param unknown $msg + */ + function error($msg) { + $this->userError = array ( + CURLE_OK, + $msg + ); + } + + /** + * return a default $ch initialized with global opt + * + * @param unknown $url + * @return resource + */ + function getch($url = null) { + return $this->curlInit ( $url ); + } + + /** + * get curl handle + * + * @param string $url + * @return resource + */ + private function curlInit($url = null) { + $ch = curl_init (); + $opt = array (); + if (isset ( $url )) { + $opt [CURLOPT_URL] = $url; + } + $opt [CURLOPT_HEADER] = false; + $opt [CURLOPT_CONNECTTIMEOUT] = 10; + $opt [CURLOPT_TIMEOUT] = 30; + $opt [CURLOPT_AUTOREFERER] = true; + $opt [CURLOPT_USERAGENT] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.47 Safari/536.11'; + $opt [CURLOPT_RETURNTRANSFER] = true; + $opt [CURLOPT_FOLLOWLOCATION] = true; + $opt [CURLOPT_MAXREDIRS] = 10; + // user defined opt + if (! empty ( $this->opt )) { + foreach ( $this->opt as $k => $v ) { + $opt [$k] = $v; + } + } + curl_setopt_array ( $ch, $opt ); + return $ch; + } +} + +class CurlMulti_Exception extends Exception { +} \ No newline at end of file diff --git a/demo/tools/http.class.php b/extensions/vendors/Http.php similarity index 100% rename from demo/tools/http.class.php rename to extensions/vendors/Http.php diff --git a/phpQuery/phpQuery.php b/phpQuery/phpQuery.php index 5d214ad..708b7a3 100644 --- a/phpQuery/phpQuery.php +++ b/phpQuery/phpQuery.php @@ -18,12 +18,4372 @@ define('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'); + +/** + * DOMEvent class. + * + * Based on + * @link http://developer.mozilla.org/En/DOM:event + * @author Tobiasz Cudnik + * @package phpQuery + * @todo implement ArrayAccess ? + */ +class DOMEvent { + /** + * Returns a boolean indicating whether the event bubbles up through the DOM or not. + * + * @var unknown_type + */ + public $bubbles = true; + /** + * Returns a boolean indicating whether the event is cancelable. + * + * @var unknown_type + */ + public $cancelable = true; + /** + * Returns a reference to the currently registered target for the event. + * + * @var unknown_type + */ + public $currentTarget; + /** + * Returns detail about the event, depending on the type of event. + * + * @var unknown_type + * @link http://developer.mozilla.org/en/DOM/event.detail + */ + public $detail; // ??? + /** + * Used to indicate which phase of the event flow is currently being evaluated. + * + * NOT IMPLEMENTED + * + * @var unknown_type + * @link http://developer.mozilla.org/en/DOM/event.eventPhase + */ + public $eventPhase; // ??? + /** + * The explicit original target of the event (Mozilla-specific). + * + * NOT IMPLEMENTED + * + * @var unknown_type + */ + public $explicitOriginalTarget; // moz only + /** + * The original target of the event, before any retargetings (Mozilla-specific). + * + * NOT IMPLEMENTED + * + * @var unknown_type + */ + public $originalTarget; // moz only + /** + * Identifies a secondary target for the event. + * + * @var unknown_type + */ + public $relatedTarget; + /** + * Returns a reference to the target to which the event was originally dispatched. + * + * @var unknown_type + */ + public $target; + /** + * Returns the time that the event was created. + * + * @var unknown_type + */ + public $timeStamp; + /** + * Returns the name of the event (case-insensitive). + */ + public $type; + public $runDefault = true; + public $data = null; + public function __construct($data) { + foreach($data as $k => $v) { + $this->$k = $v; + } + if (! $this->timeStamp) + $this->timeStamp = time(); + } + /** + * Cancels the event (if it is cancelable). + * + */ + public function preventDefault() { + $this->runDefault = false; + } + /** + * Stops the propagation of events further along in the DOM. + * + */ + public function stopPropagation() { + $this->bubbles = false; + } +} + + +/** + * DOMDocumentWrapper class simplifies work with DOMDocument. + * + * Know bug: + * - in XHTML fragments,
changes to
+ * + * @todo check XML catalogs compatibility + * @author Tobiasz Cudnik + * @package phpQuery + */ +class DOMDocumentWrapper { + /** + * @var DOMDocument + */ + public $document; + public $id; + /** + * @todo Rewrite as method and quess if null. + * @var unknown_type + */ + public $contentType = ''; + public $xpath; + public $uuid = 0; + public $data = array(); + public $dataNodes = array(); + public $events = array(); + public $eventsNodes = array(); + public $eventsGlobal = array(); + /** + * @TODO iframes support http://code.google.com/p/phpquery/issues/detail?id=28 + * @var unknown_type + */ + public $frames = array(); + /** + * Document root, by default equals to document itself. + * Used by documentFragments. + * + * @var DOMNode + */ + public $root; + public $isDocumentFragment; + public $isXML = false; + public $isXHTML = false; + public $isHTML = false; + public $charset; + public function __construct($markup = null, $contentType = null, $newDocumentID = null) { + if (isset($markup)) + $this->load($markup, $contentType, $newDocumentID); + $this->id = $newDocumentID + ? $newDocumentID + : md5(microtime()); + } + public function load($markup, $contentType = null, $newDocumentID = null) { +// phpQuery::$documents[$id] = $this; + $this->contentType = strtolower($contentType); + if ($markup instanceof DOMDOCUMENT) { + $this->document = $markup; + $this->root = $this->document; + $this->charset = $this->document->encoding; + // TODO isDocumentFragment + } else { + $loaded = $this->loadMarkup($markup); + } + if ($loaded) { +// $this->document->formatOutput = true; + $this->document->preserveWhiteSpace = true; + $this->xpath = new DOMXPath($this->document); + $this->afterMarkupLoad(); + return true; + // remember last loaded document +// return phpQuery::selectDocument($id); + } + return false; + } + protected function afterMarkupLoad() { + if ($this->isXHTML) { + $this->xpath->registerNamespace("html", "http://www.w3.org/1999/xhtml"); + } + } + protected function loadMarkup($markup) { + $loaded = false; + if ($this->contentType) { + self::debug("Load markup for content type {$this->contentType}"); + // content determined by contentType + list($contentType, $charset) = $this->contentTypeToArray($this->contentType); + switch($contentType) { + case 'text/html': + phpQuery::debug("Loading HTML, content type '{$this->contentType}'"); + $loaded = $this->loadMarkupHTML($markup, $charset); + break; + case 'text/xml': + case 'application/xhtml+xml': + phpQuery::debug("Loading XML, content type '{$this->contentType}'"); + $loaded = $this->loadMarkupXML($markup, $charset); + break; + default: + // for feeds or anything that sometimes doesn't use text/xml + if (strpos('xml', $this->contentType) !== false) { + phpQuery::debug("Loading XML, content type '{$this->contentType}'"); + $loaded = $this->loadMarkupXML($markup, $charset); + } else + phpQuery::debug("Could not determine document type from content type '{$this->contentType}'"); + } + } else { + // content type autodetection + if ($this->isXML($markup)) { + phpQuery::debug("Loading XML, isXML() == true"); + $loaded = $this->loadMarkupXML($markup); + if (! $loaded && $this->isXHTML) { + phpQuery::debug('Loading as XML failed, trying to load as HTML, isXHTML == true'); + $loaded = $this->loadMarkupHTML($markup); + } + } else { + phpQuery::debug("Loading HTML, isXML() == false"); + $loaded = $this->loadMarkupHTML($markup); + } + } + return $loaded; + } + protected function loadMarkupReset() { + $this->isXML = $this->isXHTML = $this->isHTML = false; + } + protected function documentCreate($charset, $version = '1.0') { + if (! $version) + $version = '1.0'; + $this->document = new DOMDocument($version, $charset); + $this->charset = $this->document->encoding; +// $this->document->encoding = $charset; + $this->document->formatOutput = true; + $this->document->preserveWhiteSpace = true; + } + protected function loadMarkupHTML($markup, $requestedCharset = null) { + if (phpQuery::$debug) + phpQuery::debug('Full markup load (HTML): '.substr($markup, 0, 250)); + $this->loadMarkupReset(); + $this->isHTML = true; + if (!isset($this->isDocumentFragment)) + $this->isDocumentFragment = self::isDocumentFragmentHTML($markup); + $charset = null; + $documentCharset = $this->charsetFromHTML($markup); + $addDocumentCharset = false; + if ($documentCharset) { + $charset = $documentCharset; + $markup = $this->charsetFixHTML($markup); + } else if ($requestedCharset) { + $charset = $requestedCharset; + } + if (! $charset) + $charset = phpQuery::$defaultCharset; + // HTTP 1.1 says that the default charset is ISO-8859-1 + // @see http://www.w3.org/International/O-HTTP-charset + if (! $documentCharset) { + $documentCharset = 'ISO-8859-1'; + $addDocumentCharset = true; + } + // Should be careful here, still need 'magic encoding detection' since lots of pages have other 'default encoding' + // Worse, some pages can have mixed encodings... we'll try not to worry about that + $requestedCharset = strtoupper($requestedCharset); + $documentCharset = strtoupper($documentCharset); + phpQuery::debug("DOC: $documentCharset REQ: $requestedCharset"); + if ($requestedCharset && $documentCharset && $requestedCharset !== $documentCharset) { + phpQuery::debug("CHARSET CONVERT"); + // Document Encoding Conversion + // http://code.google.com/p/phpquery/issues/detail?id=86 + if (function_exists('mb_detect_encoding')) { + $possibleCharsets = array($documentCharset, $requestedCharset, 'AUTO'); + $docEncoding = mb_detect_encoding($markup, implode(', ', $possibleCharsets)); + if (! $docEncoding) + $docEncoding = $documentCharset; // ok trust the document + phpQuery::debug("DETECTED '$docEncoding'"); + // Detected does not match what document says... + if ($docEncoding !== $documentCharset) { + // Tricky.. + } + if ($docEncoding !== $requestedCharset) { + phpQuery::debug("CONVERT $docEncoding => $requestedCharset"); + $markup = mb_convert_encoding($markup, $requestedCharset, $docEncoding); + $markup = $this->charsetAppendToHTML($markup, $requestedCharset); + $charset = $requestedCharset; + } + } else { + phpQuery::debug("TODO: charset conversion without mbstring..."); + } + } + $return = false; + if ($this->isDocumentFragment) { + phpQuery::debug("Full markup load (HTML), DocumentFragment detected, using charset '$charset'"); + $return = $this->documentFragmentLoadMarkup($this, $charset, $markup); + } else { + if ($addDocumentCharset) { + phpQuery::debug("Full markup load (HTML), appending charset: '$charset'"); + $markup = $this->charsetAppendToHTML($markup, $charset); + } + phpQuery::debug("Full markup load (HTML), documentCreate('$charset')"); + $this->documentCreate($charset); + $return = phpQuery::$debug === 2 + ? $this->document->loadHTML($markup) + : @$this->document->loadHTML($markup); + if ($return) + $this->root = $this->document; + } + if ($return && ! $this->contentType) + $this->contentType = 'text/html'; + return $return; + } + protected function loadMarkupXML($markup, $requestedCharset = null) { + if (phpQuery::$debug) + phpQuery::debug('Full markup load (XML): '.substr($markup, 0, 250)); + $this->loadMarkupReset(); + $this->isXML = true; + // check agains XHTML in contentType or markup + $isContentTypeXHTML = $this->isXHTML(); + $isMarkupXHTML = $this->isXHTML($markup); + if ($isContentTypeXHTML || $isMarkupXHTML) { + self::debug('Full markup load (XML), XHTML detected'); + $this->isXHTML = true; + } + // determine document fragment + if (! isset($this->isDocumentFragment)) + $this->isDocumentFragment = $this->isXHTML + ? self::isDocumentFragmentXHTML($markup) + : self::isDocumentFragmentXML($markup); + // this charset will be used + $charset = null; + // charset from XML declaration @var string + $documentCharset = $this->charsetFromXML($markup); + if (! $documentCharset) { + if ($this->isXHTML) { + // this is XHTML, try to get charset from content-type meta header + $documentCharset = $this->charsetFromHTML($markup); + if ($documentCharset) { + phpQuery::debug("Full markup load (XML), appending XHTML charset '$documentCharset'"); + $this->charsetAppendToXML($markup, $documentCharset); + $charset = $documentCharset; + } + } + if (! $documentCharset) { + // if still no document charset... + $charset = $requestedCharset; + } + } else if ($requestedCharset) { + $charset = $requestedCharset; + } + if (! $charset) { + $charset = phpQuery::$defaultCharset; + } + if ($requestedCharset && $documentCharset && $requestedCharset != $documentCharset) { + // TODO place for charset conversion +// $charset = $requestedCharset; + } + $return = false; + if ($this->isDocumentFragment) { + phpQuery::debug("Full markup load (XML), DocumentFragment detected, using charset '$charset'"); + $return = $this->documentFragmentLoadMarkup($this, $charset, $markup); + } else { + // FIXME ??? + if ($isContentTypeXHTML && ! $isMarkupXHTML) + if (! $documentCharset) { + phpQuery::debug("Full markup load (XML), appending charset '$charset'"); + $markup = $this->charsetAppendToXML($markup, $charset); + } + // see http://pl2.php.net/manual/en/book.dom.php#78929 + // LIBXML_DTDLOAD (>= PHP 5.1) + // does XML ctalogues works with LIBXML_NONET + // $this->document->resolveExternals = true; + // TODO test LIBXML_COMPACT for performance improvement + // create document + $this->documentCreate($charset); + if (phpversion() < 5.1) { + $this->document->resolveExternals = true; + $return = phpQuery::$debug === 2 + ? $this->document->loadXML($markup) + : @$this->document->loadXML($markup); + } else { + /** @link http://pl2.php.net/manual/en/libxml.constants.php */ + $libxmlStatic = phpQuery::$debug === 2 + ? LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET + : LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOERROR; + $return = $this->document->loadXML($markup, $libxmlStatic); +// if (! $return) +// $return = $this->document->loadHTML($markup); + } + if ($return) + $this->root = $this->document; + } + if ($return) { + if (! $this->contentType) { + if ($this->isXHTML) + $this->contentType = 'application/xhtml+xml'; + else + $this->contentType = 'text/xml'; + } + return $return; + } else { + throw new Exception("Error loading XML markup"); + } + } + protected function isXHTML($markup = null) { + if (! isset($markup)) { + return strpos($this->contentType, 'xhtml') !== false; + } + // XXX ok ? + return strpos($markup, "doctype) && is_object($dom->doctype) +// ? $dom->doctype->publicId +// : self::$defaultDoctype; + } + protected function isXML($markup) { +// return strpos($markup, ']+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', + $markup, $matches + ); + if (! isset($matches[0])) + return array(null, null); + // get attr 'content' + preg_match('@content\\s*=\\s*(["|\'])(.+?)\\1@', $matches[0], $matches); + if (! isset($matches[0])) + return array(null, null); + return $this->contentTypeToArray($matches[2]); + } + protected function charsetFromHTML($markup) { + $contentType = $this->contentTypeFromHTML($markup); + return $contentType[1]; + } + protected function charsetFromXML($markup) { + $matches; + // find declaration + preg_match('@<'.'?xml[^>]+encoding\\s*=\\s*(["|\'])(.*?)\\1@i', + $markup, $matches + ); + return isset($matches[2]) + ? strtolower($matches[2]) + : null; + } + /** + * Repositions meta[type=charset] at the start of head. Bypasses DOMDocument bug. + * + * @link http://code.google.com/p/phpquery/issues/detail?id=80 + * @param $html + */ + protected function charsetFixHTML($markup) { + $matches = array(); + // find meta tag + preg_match('@\s*]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', + $markup, $matches, PREG_OFFSET_CAPTURE + ); + if (! isset($matches[0])) + return; + $metaContentType = $matches[0][0]; + $markup = substr($markup, 0, $matches[0][1]) + .substr($markup, $matches[0][1]+strlen($metaContentType)); + $headStart = stripos($markup, ''); + $markup = substr($markup, 0, $headStart+6).$metaContentType + .substr($markup, $headStart+6); + return $markup; + } + protected function charsetAppendToHTML($html, $charset, $xhtml = false) { + // remove existing meta[type=content-type] + $html = preg_replace('@\s*]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', '', $html); + $meta = ''; + if (strpos($html, ')@s', + "{$meta}", + $html + ); + } + } else { + return preg_replace( + '@)@s', + ''.$meta, + $html + ); + } + } + protected function charsetAppendToXML($markup, $charset) { + $declaration = '<'.'?xml version="1.0" encoding="'.$charset.'"?'.'>'; + return $declaration.$markup; + } + public static function isDocumentFragmentHTML($markup) { + return stripos($markup, 'documentFragmentCreate($node, $sourceCharset); +// if ($fake === false) +// throw new Exception("Error loading documentFragment markup"); +// else +// $return = array_merge($return, +// $this->import($fake->root->childNodes) +// ); +// } else { +// $return[] = $this->document->importNode($node, true); +// } +// } +// return $return; +// } else { +// // string markup +// $fake = $this->documentFragmentCreate($source, $sourceCharset); +// if ($fake === false) +// throw new Exception("Error loading documentFragment markup"); +// else +// return $this->import($fake->root->childNodes); +// } + if (is_array($source) || $source instanceof DOMNODELIST) { + // dom nodes + self::debug('Importing nodes to document'); + foreach($source as $node) + $return[] = $this->document->importNode($node, true); + } else { + // string markup + $fake = $this->documentFragmentCreate($source, $sourceCharset); + if ($fake === false) + throw new Exception("Error loading documentFragment markup"); + else + return $this->import($fake->root->childNodes); + } + return $return; + } + /** + * Creates new document fragment. + * + * @param $source + * @return DOMDocumentWrapper + */ + protected function documentFragmentCreate($source, $charset = null) { + $fake = new DOMDocumentWrapper(); + $fake->contentType = $this->contentType; + $fake->isXML = $this->isXML; + $fake->isHTML = $this->isHTML; + $fake->isXHTML = $this->isXHTML; + $fake->root = $fake->document; + if (! $charset) + $charset = $this->charset; +// $fake->documentCreate($this->charset); + if ($source instanceof DOMNODE && !($source instanceof DOMNODELIST)) + $source = array($source); + if (is_array($source) || $source instanceof DOMNODELIST) { + // dom nodes + // load fake document + if (! $this->documentFragmentLoadMarkup($fake, $charset)) + return false; + $nodes = $fake->import($source); + foreach($nodes as $node) + $fake->root->appendChild($node); + } else { + // string markup + $this->documentFragmentLoadMarkup($fake, $charset, $source); + } + return $fake; + } + /** + * + * @param $document DOMDocumentWrapper + * @param $markup + * @return $document + */ + private function documentFragmentLoadMarkup($fragment, $charset, $markup = null) { + // TODO error handling + // TODO copy doctype + // tempolary turn off + $fragment->isDocumentFragment = false; + if ($fragment->isXML) { + if ($fragment->isXHTML) { + // add FAKE element to set default namespace + $fragment->loadMarkupXML('' + .'' + .''.$markup.''); + $fragment->root = $fragment->document->firstChild->nextSibling; + } else { + $fragment->loadMarkupXML(''.$markup.''); + $fragment->root = $fragment->document->firstChild; + } + } else { + $markup2 = phpQuery::$defaultDoctype.''; + $noBody = strpos($markup, 'loadMarkupHTML($markup2); + // TODO resolv body tag merging issue + $fragment->root = $noBody + ? $fragment->document->firstChild->nextSibling->firstChild->nextSibling + : $fragment->document->firstChild->nextSibling->firstChild->nextSibling; + } + if (! $fragment->root) + return false; + $fragment->isDocumentFragment = true; + return true; + } + protected function documentFragmentToMarkup($fragment) { + phpQuery::debug('documentFragmentToMarkup'); + $tmp = $fragment->isDocumentFragment; + $fragment->isDocumentFragment = false; + $markup = $fragment->markup(); + if ($fragment->isXML) { + $markup = substr($markup, 0, strrpos($markup, '')); + if ($fragment->isXHTML) { + $markup = substr($markup, strpos($markup, '')+6); + } + } else { + $markup = substr($markup, strpos($markup, '')+6); + $markup = substr($markup, 0, strrpos($markup, '')); + } + $fragment->isDocumentFragment = $tmp; + if (phpQuery::$debug) + phpQuery::debug('documentFragmentToMarkup: '.substr($markup, 0, 150)); + return $markup; + } + /** + * Return document markup, starting with optional $nodes as root. + * + * @param $nodes DOMNode|DOMNodeList + * @return string + */ + public function markup($nodes = null, $innerMarkup = false) { + if (isset($nodes) && count($nodes) == 1 && $nodes[0] instanceof DOMDOCUMENT) + $nodes = null; + if (isset($nodes)) { + $markup = ''; + if (!is_array($nodes) && !($nodes instanceof DOMNODELIST) ) + $nodes = array($nodes); + if ($this->isDocumentFragment && ! $innerMarkup) + foreach($nodes as $i => $node) + if ($node->isSameNode($this->root)) { + // var_dump($node); + $nodes = array_slice($nodes, 0, $i) + + phpQuery::DOMNodeListToArray($node->childNodes) + + array_slice($nodes, $i+1); + } + if ($this->isXML && ! $innerMarkup) { + self::debug("Getting outerXML with charset '{$this->charset}'"); + // we need outerXML, so we can benefit from + // $node param support in saveXML() + foreach($nodes as $node) + $markup .= $this->document->saveXML($node); + } else { + $loop = array(); + if ($innerMarkup) + foreach($nodes as $node) { + if ($node->childNodes) + foreach($node->childNodes as $child) + $loop[] = $child; + else + $loop[] = $node; + } + else + $loop = $nodes; + self::debug("Getting markup, moving selected nodes (".count($loop).") to new DocumentFragment"); + $fake = $this->documentFragmentCreate($loop); + $markup = $this->documentFragmentToMarkup($fake); + } + if ($this->isXHTML) { + self::debug("Fixing XHTML"); + $markup = self::markupFixXHTML($markup); + } + self::debug("Markup: ".substr($markup, 0, 250)); + return $markup; + } else { + if ($this->isDocumentFragment) { + // documentFragment, html only... + self::debug("Getting markup, DocumentFragment detected"); +// return $this->markup( +//// $this->document->getElementsByTagName('body')->item(0) +// $this->document->root, true +// ); + $markup = $this->documentFragmentToMarkup($this); + // no need for markupFixXHTML, as it's done thought markup($nodes) method + return $markup; + } else { + self::debug("Getting markup (".($this->isXML?'XML':'HTML')."), final with charset '{$this->charset}'"); + $markup = $this->isXML + ? $this->document->saveXML() + : $this->document->saveHTML(); + if ($this->isXHTML) { + self::debug("Fixing XHTML"); + $markup = self::markupFixXHTML($markup); + } + self::debug("Markup: ".substr($markup, 0, 250)); + return $markup; + } + } + } + protected static function markupFixXHTML($markup) { + $markup = self::expandEmptyTag('script', $markup); + $markup = self::expandEmptyTag('select', $markup); + $markup = self::expandEmptyTag('textarea', $markup); + return $markup; + } + public static function debug($text) { + phpQuery::debug($text); + } + /** + * expandEmptyTag + * + * @param $tag + * @param $xml + * @return unknown_type + * @author mjaque at ilkebenson dot com + * @link http://php.net/manual/en/domdocument.savehtml.php#81256 + */ + public static function expandEmptyTag($tag, $xml){ + $indice = 0; + while ($indice< strlen($xml)){ + $pos = strpos($xml, "<$tag ", $indice); + if ($pos){ + $posCierre = strpos($xml, ">", $pos); + if ($xml[$posCierre-1] == "/"){ + $xml = substr_replace($xml, ">", $posCierre-1, 2); + } + $indice = $posCierre; + } + else break; + } + return $xml; + } +} + +/** + * Event handling class. + * + * @author Tobiasz Cudnik + * @package phpQuery + * @static + */ +abstract class phpQueryEvents { + /** + * Trigger a type of event on every matched element. + * + * @param DOMNode|phpQueryObject|string $document + * @param unknown_type $type + * @param unknown_type $data + * + * @TODO exclusive events (with !) + * @TODO global events (test) + * @TODO support more than event in $type (space-separated) + */ + public static function trigger($document, $type, $data = array(), $node = null) { + // trigger: function(type, data, elem, donative, extra) { + $documentID = phpQuery::getDocumentID($document); + $namespace = null; + if (strpos($type, '.') !== false) + list($name, $namespace) = explode('.', $type); + else + $name = $type; + if (! $node) { + if (self::issetGlobal($documentID, $type)) { + $pq = phpQuery::getDocument($documentID); + // TODO check add($pq->document) + $pq->find('*')->add($pq->document) + ->trigger($type, $data); + } + } else { + if (isset($data[0]) && $data[0] instanceof DOMEvent) { + $event = $data[0]; + $event->relatedTarget = $event->target; + $event->target = $node; + $data = array_slice($data, 1); + } else { + $event = new DOMEvent(array( + 'type' => $type, + 'target' => $node, + 'timeStamp' => time(), + )); + } + $i = 0; + while($node) { + // TODO whois + phpQuery::debug("Triggering ".($i?"bubbled ":'')."event '{$type}' on " + ."node \n");//.phpQueryObject::whois($node)."\n"); + $event->currentTarget = $node; + $eventNode = self::getNode($documentID, $node); + if (isset($eventNode->eventHandlers)) { + foreach($eventNode->eventHandlers as $eventType => $handlers) { + $eventNamespace = null; + if (strpos($type, '.') !== false) + list($eventName, $eventNamespace) = explode('.', $eventType); + else + $eventName = $eventType; + if ($name != $eventName) + continue; + if ($namespace && $eventNamespace && $namespace != $eventNamespace) + continue; + foreach($handlers as $handler) { + phpQuery::debug("Calling event handler\n"); + $event->data = $handler['data'] + ? $handler['data'] + : null; + $params = array_merge(array($event), $data); + $return = phpQuery::callbackRun($handler['callback'], $params); + if ($return === false) { + $event->bubbles = false; + } + } + } + } + // to bubble or not to bubble... + if (! $event->bubbles) + break; + $node = $node->parentNode; + $i++; + } + } + } + /** + * Binds a handler to one or more events (like click) for each matched element. + * Can also bind custom events. + * + * @param DOMNode|phpQueryObject|string $document + * @param unknown_type $type + * @param unknown_type $data Optional + * @param unknown_type $callback + * + * @TODO support '!' (exclusive) events + * @TODO support more than event in $type (space-separated) + * @TODO support binding to global events + */ + public static function add($document, $node, $type, $data, $callback = null) { + phpQuery::debug("Binding '$type' event"); + $documentID = phpQuery::getDocumentID($document); +// if (is_null($callback) && is_callable($data)) { +// $callback = $data; +// $data = null; +// } + $eventNode = self::getNode($documentID, $node); + if (! $eventNode) + $eventNode = self::setNode($documentID, $node); + if (!isset($eventNode->eventHandlers[$type])) + $eventNode->eventHandlers[$type] = array(); + $eventNode->eventHandlers[$type][] = array( + 'callback' => $callback, + 'data' => $data, + ); + } + /** + * Enter description here... + * + * @param DOMNode|phpQueryObject|string $document + * @param unknown_type $type + * @param unknown_type $callback + * + * @TODO namespace events + * @TODO support more than event in $type (space-separated) + */ + public static function remove($document, $node, $type = null, $callback = null) { + $documentID = phpQuery::getDocumentID($document); + $eventNode = self::getNode($documentID, $node); + if (is_object($eventNode) && isset($eventNode->eventHandlers[$type])) { + if ($callback) { + foreach($eventNode->eventHandlers[$type] as $k => $handler) + if ($handler['callback'] == $callback) + unset($eventNode->eventHandlers[$type][$k]); + } else { + unset($eventNode->eventHandlers[$type]); + } + } + } + protected static function getNode($documentID, $node) { + foreach(phpQuery::$documents[$documentID]->eventsNodes as $eventNode) { + if ($node->isSameNode($eventNode)) + return $eventNode; + } + } + protected static function setNode($documentID, $node) { + phpQuery::$documents[$documentID]->eventsNodes[] = $node; + return phpQuery::$documents[$documentID]->eventsNodes[ + count(phpQuery::$documents[$documentID]->eventsNodes)-1 + ]; + } + protected static function issetGlobal($documentID, $type) { + return isset(phpQuery::$documents[$documentID]) + ? in_array($type, phpQuery::$documents[$documentID]->eventsGlobal) + : false; + } +} + + +interface ICallbackNamed { + function hasName(); + function getName(); +} +/** + * Callback class introduces currying-like pattern. + * + * Example: + * function foo($param1, $param2, $param3) { + * var_dump($param1, $param2, $param3); + * } + * $fooCurried = new Callback('foo', + * 'param1 is now statically set', + * new CallbackParam, new CallbackParam + * ); + * phpQuery::callbackRun($fooCurried, + * array('param2 value', 'param3 value' + * ); + * + * Callback class is supported in all phpQuery methods which accepts callbacks. + * + * @link http://code.google.com/p/phpquery/wiki/Callbacks#Param_Structures + * @author Tobiasz Cudnik + * + * @TODO??? return fake forwarding function created via create_function + * @TODO honor paramStructure + */ +class Callback + implements ICallbackNamed { + public $callback = null; + public $params = null; + protected $name; + public function __construct($callback, $param1 = null, $param2 = null, + $param3 = null) { + $params = func_get_args(); + $params = array_slice($params, 1); + if ($callback instanceof Callback) { + // TODO implement recurention + } else { + $this->callback = $callback; + $this->params = $params; + } + } + public function getName() { + return 'Callback: '.$this->name; + } + public function hasName() { + return isset($this->name) && $this->name; + } + public function setName($name) { + $this->name = $name; + return $this; + } + // TODO test me +// public function addParams() { +// $params = func_get_args(); +// return new Callback($this->callback, $this->params+$params); +// } +} +/** + * Shorthand for new Callback(create_function(...), ...); + * + * @author Tobiasz Cudnik + */ +class CallbackBody extends Callback { + public function __construct($paramList, $code, $param1 = null, $param2 = null, + $param3 = null) { + $params = func_get_args(); + $params = array_slice($params, 2); + $this->callback = create_function($paramList, $code); + $this->params = $params; + } +} +/** + * Callback type which on execution returns reference passed during creation. + * + * @author Tobiasz Cudnik + */ +class CallbackReturnReference extends Callback + implements ICallbackNamed { + protected $reference; + public function __construct(&$reference, $name = null){ + $this->reference =& $reference; + $this->callback = array($this, 'callback'); + } + public function callback() { + return $this->reference; + } + public function getName() { + return 'Callback: '.$this->name; + } + public function hasName() { + return isset($this->name) && $this->name; + } +} +/** + * Callback type which on execution returns value passed during creation. + * + * @author Tobiasz Cudnik + */ +class CallbackReturnValue extends Callback + implements ICallbackNamed { + protected $value; + protected $name; + public function __construct($value, $name = null){ + $this->value =& $value; + $this->name = $name; + $this->callback = array($this, 'callback'); + } + public function callback() { + return $this->value; + } + public function __toString() { + return $this->getName(); + } + public function getName() { + return 'Callback: '.$this->name; + } + public function hasName() { + return isset($this->name) && $this->name; + } +} +/** + * CallbackParameterToReference can be used when we don't really want a callback, + * only parameter passed to it. CallbackParameterToReference takes first + * parameter's value and passes it to reference. + * + * @author Tobiasz Cudnik + */ +class CallbackParameterToReference extends Callback { + /** + * @param $reference + * @TODO implement $paramIndex; + * param index choose which callback param will be passed to reference + */ + public function __construct(&$reference){ + $this->callback =& $reference; + } +} +//class CallbackReference extends Callback { +// /** +// * +// * @param $reference +// * @param $paramIndex +// * @todo implement $paramIndex; param index choose which callback param will be passed to reference +// */ +// public function __construct(&$reference, $name = null){ +// $this->callback =& $reference; +// } +//} +class CallbackParam {} + +/** + * Class representing phpQuery objects. + * + * @author Tobiasz Cudnik + * @package phpQuery + * @method phpQueryObject clone() clone() + * @method phpQueryObject empty() empty() + * @method phpQueryObject next() next($selector = null) + * @method phpQueryObject prev() prev($selector = null) + * @property Int $length + */ +class phpQueryObject + implements Iterator, Countable, ArrayAccess { + public $documentID = null; + /** + * DOMDocument class. + * + * @var DOMDocument + */ + public $document = null; + public $charset = null; + /** + * + * @var DOMDocumentWrapper + */ + public $documentWrapper = null; + /** + * XPath interface. + * + * @var DOMXPath + */ + public $xpath = null; + /** + * Stack of selected elements. + * @TODO refactor to ->nodes + * @var array + */ + public $elements = array(); + /** + * @access private + */ + protected $elementsBackup = array(); + /** + * @access private + */ + protected $previous = null; + /** + * @access private + * @TODO deprecate + */ + protected $root = array(); + /** + * Indicated if doument is just a fragment (no tag). + * + * Every document is realy a full document, so even documentFragments can + * be queried against , but getDocument(id)->htmlOuter() will return + * only contents of . + * + * @var bool + */ + public $documentFragment = true; + /** + * Iterator interface helper + * @access private + */ + protected $elementsInterator = array(); + /** + * Iterator interface helper + * @access private + */ + protected $valid = false; + /** + * Iterator interface helper + * @access private + */ + protected $current = null; + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function __construct($documentID) { +// if ($documentID instanceof self) +// var_dump($documentID->getDocumentID()); + $id = $documentID instanceof self + ? $documentID->getDocumentID() + : $documentID; +// var_dump($id); + if (! isset(phpQuery::$documents[$id] )) { +// var_dump(phpQuery::$documents); + throw new Exception("Document with ID '{$id}' isn't loaded. Use phpQuery::newDocument(\$html) or phpQuery::newDocumentFile(\$file) first."); + } + $this->documentID = $id; + $this->documentWrapper =& phpQuery::$documents[$id]; + $this->document =& $this->documentWrapper->document; + $this->xpath =& $this->documentWrapper->xpath; + $this->charset =& $this->documentWrapper->charset; + $this->documentFragment =& $this->documentWrapper->isDocumentFragment; + // TODO check $this->DOM->documentElement; +// $this->root = $this->document->documentElement; + $this->root =& $this->documentWrapper->root; +// $this->toRoot(); + $this->elements = array($this->root); + } + /** + * + * @access private + * @param $attr + * @return unknown_type + */ + public function __get($attr) { + switch($attr) { + // FIXME doesnt work at all ? + case 'length': + return $this->size(); + break; + default: + return $this->$attr; + } + } + /** + * Saves actual object to $var by reference. + * Useful when need to break chain. + * @param phpQueryObject $var + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function toReference(&$var) { + return $var = $this; + } + public function documentFragment($state = null) { + if ($state) { + phpQuery::$documents[$this->getDocumentID()]['documentFragment'] = $state; + return $this; + } + return $this->documentFragment; + } + /** + * @access private + * @TODO documentWrapper + */ + protected function isRoot( $node) { +// return $node instanceof DOMDOCUMENT || $node->tagName == 'html'; + return $node instanceof DOMDOCUMENT + || ($node instanceof DOMELEMENT && $node->tagName == 'html') + || $this->root->isSameNode($node); + } + /** + * @access private + */ + protected function stackIsRoot() { + return $this->size() == 1 && $this->isRoot($this->elements[0]); + } + /** + * Enter description here... + * NON JQUERY METHOD + * + * Watch out, it doesn't creates new instance, can be reverted with end(). + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function toRoot() { + $this->elements = array($this->root); + return $this; +// return $this->newInstance(array($this->root)); + } + /** + * Saves object's DocumentID to $var by reference. + * + * $myDocumentId; + * phpQuery::newDocument('
') + * ->getDocumentIDRef($myDocumentId) + * ->find('div')->... + * + * + * @param unknown_type $domId + * @see phpQuery::newDocument + * @see phpQuery::newDocumentFile + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function getDocumentIDRef(&$documentID) { + $documentID = $this->getDocumentID(); + return $this; + } + /** + * Returns object with stack set to document root. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function getDocument() { + return phpQuery::getDocument($this->getDocumentID()); + } + /** + * + * @return DOMDocument + */ + public function getDOMDocument() { + return $this->document; + } + /** + * Get object's Document ID. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function getDocumentID() { + return $this->documentID; + } + /** + * Unloads whole document from memory. + * CAUTION! None further operations will be possible on this document. + * All objects refering to it will be useless. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function unloadDocument() { + phpQuery::unloadDocuments($this->getDocumentID()); + } + public function isHTML() { + return $this->documentWrapper->isHTML; + } + public function isXHTML() { + return $this->documentWrapper->isXHTML; + } + public function isXML() { + return $this->documentWrapper->isXML; + } + /** + * Enter description here... + * + * @link http://docs.jquery.com/Ajax/serialize + * @return string + */ + public function serialize() { + return phpQuery::param($this->serializeArray()); + } + /** + * Enter description here... + * + * @link http://docs.jquery.com/Ajax/serializeArray + * @return array + */ + public function serializeArray($submit = null) { + $source = $this->filter('form, input, select, textarea') + ->find('input, select, textarea') + ->andSelf() + ->not('form'); + $return = array(); +// $source->dumpDie(); + foreach($source as $input) { + $input = phpQuery::pq($input); + if ($input->is('[disabled]')) + continue; + if (!$input->is('[name]')) + continue; + if ($input->is('[type=checkbox]') && !$input->is('[checked]')) + continue; + // jquery diff + if ($submit && $input->is('[type=submit]')) { + if ($submit instanceof DOMELEMENT && ! $input->elements[0]->isSameNode($submit)) + continue; + else if (is_string($submit) && $input->attr('name') != $submit) + continue; + } + $return[] = array( + 'name' => $input->attr('name'), + 'value' => $input->val(), + ); + } + return $return; + } + /** + * @access private + */ + protected function debug($in) { + if (! phpQuery::$debug ) + return; + print('
');
+		print_r($in);
+		// file debug
+//		file_put_contents(dirname(__FILE__).'/phpQuery.log', print_r($in, true)."\n", FILE_APPEND);
+		// quite handy debug trace
+//		if ( is_array($in))
+//			print_r(array_slice(debug_backtrace(), 3));
+		print("
\n"); + } + /** + * @access private + */ + protected function isRegexp($pattern) { + return in_array( + $pattern[ mb_strlen($pattern)-1 ], + array('^','*','$') + ); + } + /** + * Determines if $char is really a char. + * + * @param string $char + * @return bool + * @todo rewrite me to charcode range ! ;) + * @access private + */ + protected function isChar($char) { + return extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? mb_eregi('\w', $char) + : preg_match('@\w@', $char); + } + /** + * @access private + */ + protected function parseSelector($query) { + // clean spaces + // TODO include this inside parsing ? + $query = trim( + preg_replace('@\s+@', ' ', + preg_replace('@\s*(>|\\+|~)\s*@', '\\1', $query) + ) + ); + $queries = array(array()); + if (! $query) + return $queries; + $return =& $queries[0]; + $specialChars = array('>',' '); +// $specialCharsMapping = array('/' => '>'); + $specialCharsMapping = array(); + $strlen = mb_strlen($query); + $classChars = array('.', '-'); + $pseudoChars = array('-'); + $tagChars = array('*', '|', '-'); + // split multibyte string + // http://code.google.com/p/phpquery/issues/detail?id=76 + $_query = array(); + for ($i=0; $i<$strlen; $i++) + $_query[] = mb_substr($query, $i, 1); + $query = $_query; + // it works, but i dont like it... + $i = 0; + while( $i < $strlen) { + $c = $query[$i]; + $tmp = ''; + // TAG + if ($this->isChar($c) || in_array($c, $tagChars)) { + while(isset($query[$i]) + && ($this->isChar($query[$i]) || in_array($query[$i], $tagChars))) { + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // IDs + } else if ( $c == '#') { + $i++; + while( isset($query[$i]) && ($this->isChar($query[$i]) || $query[$i] == '-')) { + $tmp .= $query[$i]; + $i++; + } + $return[] = '#'.$tmp; + // SPECIAL CHARS + } else if (in_array($c, $specialChars)) { + $return[] = $c; + $i++; + // MAPPED SPECIAL MULTICHARS +// } else if ( $c.$query[$i+1] == '//') { +// $return[] = ' '; +// $i = $i+2; + // MAPPED SPECIAL CHARS + } else if ( isset($specialCharsMapping[$c])) { + $return[] = $specialCharsMapping[$c]; + $i++; + // COMMA + } else if ( $c == ',') { + $queries[] = array(); + $return =& $queries[ count($queries)-1 ]; + $i++; + while( isset($query[$i]) && $query[$i] == ' ') + $i++; + // CLASSES + } else if ($c == '.') { + while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $classChars))) { + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // ~ General Sibling Selector + } else if ($c == '~') { + $spaceAllowed = true; + $tmp .= $query[$i++]; + while( isset($query[$i]) + && ($this->isChar($query[$i]) + || in_array($query[$i], $classChars) + || $query[$i] == '*' + || ($query[$i] == ' ' && $spaceAllowed) + )) { + if ($query[$i] != ' ') + $spaceAllowed = false; + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // + Adjacent sibling selectors + } else if ($c == '+') { + $spaceAllowed = true; + $tmp .= $query[$i++]; + while( isset($query[$i]) + && ($this->isChar($query[$i]) + || in_array($query[$i], $classChars) + || $query[$i] == '*' + || ($spaceAllowed && $query[$i] == ' ') + )) { + if ($query[$i] != ' ') + $spaceAllowed = false; + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // ATTRS + } else if ($c == '[') { + $stack = 1; + $tmp .= $c; + while( isset($query[++$i])) { + $tmp .= $query[$i]; + if ( $query[$i] == '[') { + $stack++; + } else if ( $query[$i] == ']') { + $stack--; + if (! $stack ) + break; + } + } + $return[] = $tmp; + $i++; + // PSEUDO CLASSES + } else if ($c == ':') { + $stack = 1; + $tmp .= $query[$i++]; + while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $pseudoChars))) { + $tmp .= $query[$i]; + $i++; + } + // with arguments ? + if ( isset($query[$i]) && $query[$i] == '(') { + $tmp .= $query[$i]; + $stack = 1; + while( isset($query[++$i])) { + $tmp .= $query[$i]; + if ( $query[$i] == '(') { + $stack++; + } else if ( $query[$i] == ')') { + $stack--; + if (! $stack ) + break; + } + } + $return[] = $tmp; + $i++; + } else { + $return[] = $tmp; + } + } else { + $i++; + } + } + foreach($queries as $k => $q) { + if (isset($q[0])) { + if (isset($q[0][0]) && $q[0][0] == ':') + array_unshift($queries[$k], '*'); + if ($q[0] != '>') + array_unshift($queries[$k], ' '); + } + } + return $queries; + } + /** + * Return matched DOM nodes. + * + * @param int $index + * @return array|DOMElement Single DOMElement or array of DOMElement. + */ + public function get($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { + $return = isset($index) + ? (isset($this->elements[$index]) ? $this->elements[$index] : null) + : $this->elements; + // pass thou callbacks + $args = func_get_args(); + $args = array_slice($args, 1); + foreach($args as $callback) { + if (is_array($return)) + foreach($return as $k => $v) + $return[$k] = phpQuery::callbackRun($callback, array($v)); + else + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + /** + * Return matched DOM nodes. + * jQuery difference. + * + * @param int $index + * @return array|string Returns string if $index != null + * @todo implement callbacks + * @todo return only arrays ? + * @todo maybe other name... + */ + public function getString($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if ($index) + $return = $this->eq($index)->text(); + else { + $return = array(); + for($i = 0; $i < $this->size(); $i++) { + $return[] = $this->eq($i)->text(); + } + } + // pass thou callbacks + $args = func_get_args(); + $args = array_slice($args, 1); + foreach($args as $callback) { + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + /** + * Return matched DOM nodes. + * jQuery difference. + * + * @param int $index + * @return array|string Returns string if $index != null + * @todo implement callbacks + * @todo return only arrays ? + * @todo maybe other name... + */ + public function getStrings($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if ($index) + $return = $this->eq($index)->text(); + else { + $return = array(); + for($i = 0; $i < $this->size(); $i++) { + $return[] = $this->eq($i)->text(); + } + // pass thou callbacks + $args = func_get_args(); + $args = array_slice($args, 1); + } + foreach($args as $callback) { + if (is_array($return)) + foreach($return as $k => $v) + $return[$k] = phpQuery::callbackRun($callback, array($v)); + else + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + /** + * Returns new instance of actual class. + * + * @param array $newStack Optional. Will replace old stack with new and move old one to history.c + */ + public function newInstance($newStack = null) { + $class = get_class($this); + // support inheritance by passing old object to overloaded constructor + $new = $class != 'phpQuery' + ? new $class($this, $this->getDocumentID()) + : new phpQueryObject($this->getDocumentID()); + $new->previous = $this; + if (is_null($newStack)) { + $new->elements = $this->elements; + if ($this->elementsBackup) + $this->elements = $this->elementsBackup; + } else if (is_string($newStack)) { + $new->elements = phpQuery::pq($newStack, $this->getDocumentID())->stack(); + } else { + $new->elements = $newStack; + } + return $new; + } + /** + * Enter description here... + * + * In the future, when PHP will support XLS 2.0, then we would do that this way: + * contains(tokenize(@class, '\s'), "something") + * @param unknown_type $class + * @param unknown_type $node + * @return boolean + * @access private + */ + protected function matchClasses($class, $node) { + // multi-class + if ( mb_strpos($class, '.', 1)) { + $classes = explode('.', substr($class, 1)); + $classesCount = count( $classes ); + $nodeClasses = explode(' ', $node->getAttribute('class') ); + $nodeClassesCount = count( $nodeClasses ); + if ( $classesCount > $nodeClassesCount ) + return false; + $diff = count( + array_diff( + $classes, + $nodeClasses + ) + ); + if (! $diff ) + return true; + // single-class + } else { + return in_array( + // strip leading dot from class name + substr($class, 1), + // get classes for element as array + explode(' ', $node->getAttribute('class') ) + ); + } + } + /** + * @access private + */ + protected function runQuery($XQuery, $selector = null, $compare = null) { + if ($compare && ! method_exists($this, $compare)) + return false; + $stack = array(); + if (! $this->elements) + $this->debug('Stack empty, skipping...'); +// var_dump($this->elements[0]->nodeType); + // element, document + foreach($this->stack(array(1, 9, 13)) as $k => $stackNode) { + $detachAfter = false; + // to work on detached nodes we need temporary place them somewhere + // thats because context xpath queries sucks ;] + $testNode = $stackNode; + while ($testNode) { + if (! $testNode->parentNode && ! $this->isRoot($testNode)) { + $this->root->appendChild($testNode); + $detachAfter = $testNode; + break; + } + $testNode = isset($testNode->parentNode) + ? $testNode->parentNode + : null; + } + // XXX tmp ? + $xpath = $this->documentWrapper->isXHTML + ? $this->getNodeXpath($stackNode, 'html') + : $this->getNodeXpath($stackNode); + // FIXME pseudoclasses-only query, support XML + $query = $XQuery == '//' && $xpath == '/html[1]' + ? '//*' + : $xpath.$XQuery; + $this->debug("XPATH: {$query}"); + // run query, get elements + $nodes = $this->xpath->query($query); + $this->debug("QUERY FETCHED"); + if (! $nodes->length ) + $this->debug('Nothing found'); + $debug = array(); + foreach($nodes as $node) { + $matched = false; + if ( $compare) { + phpQuery::$debug ? + $this->debug("Found: ".$this->whois( $node ).", comparing with {$compare}()") + : null; + $phpQueryDebug = phpQuery::$debug; + phpQuery::$debug = false; + // TODO ??? use phpQuery::callbackRun() + if (call_user_func_array(array($this, $compare), array($selector, $node))) + $matched = true; + phpQuery::$debug = $phpQueryDebug; + } else { + $matched = true; + } + if ( $matched) { + if (phpQuery::$debug) + $debug[] = $this->whois( $node ); + $stack[] = $node; + } + } + if (phpQuery::$debug) { + $this->debug("Matched ".count($debug).": ".implode(', ', $debug)); + } + if ($detachAfter) + $this->root->removeChild($detachAfter); + } + $this->elements = $stack; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function find($selectors, $context = null, $noHistory = false) { + if (!$noHistory) + // backup last stack /for end()/ + $this->elementsBackup = $this->elements; + // allow to define context + // TODO combine code below with phpQuery::pq() context guessing code + // as generic function + if ($context) { + if (! is_array($context) && $context instanceof DOMELEMENT) + $this->elements = array($context); + else if (is_array($context)) { + $this->elements = array(); + foreach ($context as $c) + if ($c instanceof DOMELEMENT) + $this->elements[] = $c; + } else if ( $context instanceof self ) + $this->elements = $context->elements; + } + $queries = $this->parseSelector($selectors); + $this->debug(array('FIND', $selectors, $queries)); + $XQuery = ''; + // remember stack state because of multi-queries + $oldStack = $this->elements; + // here we will be keeping found elements + $stack = array(); + foreach($queries as $selector) { + $this->elements = $oldStack; + $delimiterBefore = false; + foreach($selector as $s) { + // TAG + $isTag = extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? mb_ereg_match('^[\w|\||-]+$', $s) || $s == '*' + : preg_match('@^[\w|\||-]+$@', $s) || $s == '*'; + if ($isTag) { + if ($this->isXML()) { + // namespace support + if (mb_strpos($s, '|') !== false) { + $ns = $tag = null; + list($ns, $tag) = explode('|', $s); + $XQuery .= "$ns:$tag"; + } else if ($s == '*') { + $XQuery .= "*"; + } else { + $XQuery .= "*[local-name()='$s']"; + } + } else { + $XQuery .= $s; + } + // ID + } else if ($s[0] == '#') { + if ($delimiterBefore) + $XQuery .= '*'; + $XQuery .= "[@id='".substr($s, 1)."']"; + // ATTRIBUTES + } else if ($s[0] == '[') { + if ($delimiterBefore) + $XQuery .= '*'; + // strip side brackets + $attr = trim($s, ']['); + $execute = false; + // attr with specifed value + if (mb_strpos($s, '=')) { + $value = null; + list($attr, $value) = explode('=', $attr); + $value = trim($value, "'\""); + if ($this->isRegexp($attr)) { + // cut regexp character + $attr = substr($attr, 0, -1); + $execute = true; + $XQuery .= "[@{$attr}]"; + } else { + $XQuery .= "[@{$attr}='{$value}']"; + } + // attr without specified value + } else { + $XQuery .= "[@{$attr}]"; + } + if ($execute) { + $this->runQuery($XQuery, $s, 'is'); + $XQuery = ''; + if (! $this->length()) + break; + } + // CLASSES + } else if ($s[0] == '.') { + // TODO use return $this->find("./self::*[contains(concat(\" \",@class,\" \"), \" $class \")]"); + // thx wizDom ;) + if ($delimiterBefore) + $XQuery .= '*'; + $XQuery .= '[@class]'; + $this->runQuery($XQuery, $s, 'matchClasses'); + $XQuery = ''; + if (! $this->length() ) + break; + // ~ General Sibling Selector + } else if ($s[0] == '~') { + $this->runQuery($XQuery); + $XQuery = ''; + $this->elements = $this + ->siblings( + substr($s, 1) + )->elements; + if (! $this->length() ) + break; + // + Adjacent sibling selectors + } else if ($s[0] == '+') { + // TODO /following-sibling:: + $this->runQuery($XQuery); + $XQuery = ''; + $subSelector = substr($s, 1); + $subElements = $this->elements; + $this->elements = array(); + foreach($subElements as $node) { + // search first DOMElement sibling + $test = $node->nextSibling; + while($test && ! ($test instanceof DOMELEMENT)) + $test = $test->nextSibling; + if ($test && $this->is($subSelector, $test)) + $this->elements[] = $test; + } + if (! $this->length() ) + break; + // PSEUDO CLASSES + } else if ($s[0] == ':') { + // TODO optimization for :first :last + if ($XQuery) { + $this->runQuery($XQuery); + $XQuery = ''; + } + if (! $this->length()) + break; + $this->pseudoClasses($s); + if (! $this->length()) + break; + // DIRECT DESCENDANDS + } else if ($s == '>') { + $XQuery .= '/'; + $delimiterBefore = 2; + // ALL DESCENDANDS + } else if ($s == ' ') { + $XQuery .= '//'; + $delimiterBefore = 2; + // ERRORS + } else { + phpQuery::debug("Unrecognized token '$s'"); + } + $delimiterBefore = $delimiterBefore === 2; + } + // run query if any + if ($XQuery && $XQuery != '//') { + $this->runQuery($XQuery); + $XQuery = ''; + } + foreach($this->elements as $node) + if (! $this->elementsContainsNode($node, $stack)) + $stack[] = $node; + } + $this->elements = $stack; + return $this->newInstance(); + } + /** + * @todo create API for classes with pseudoselectors + * @access private + */ + protected function pseudoClasses($class) { + // TODO clean args parsing ? + $class = ltrim($class, ':'); + $haveArgs = mb_strpos($class, '('); + if ($haveArgs !== false) { + $args = substr($class, $haveArgs+1, -1); + $class = substr($class, 0, $haveArgs); + } + switch($class) { + case 'even': + case 'odd': + $stack = array(); + foreach($this->elements as $i => $node) { + if ($class == 'even' && ($i%2) == 0) + $stack[] = $node; + else if ( $class == 'odd' && $i % 2 ) + $stack[] = $node; + } + $this->elements = $stack; + break; + case 'eq': + $k = intval($args); + $this->elements = isset( $this->elements[$k] ) + ? array( $this->elements[$k] ) + : array(); + break; + case 'gt': + $this->elements = array_slice($this->elements, $args+1); + break; + case 'lt': + $this->elements = array_slice($this->elements, 0, $args+1); + break; + case 'first': + if (isset($this->elements[0])) + $this->elements = array($this->elements[0]); + break; + case 'last': + if ($this->elements) + $this->elements = array($this->elements[count($this->elements)-1]); + break; + /*case 'parent': + $stack = array(); + foreach($this->elements as $node) { + if ( $node->childNodes->length ) + $stack[] = $node; + } + $this->elements = $stack; + break;*/ + case 'contains': + $text = trim($args, "\"'"); + $stack = array(); + foreach($this->elements as $node) { + if (mb_stripos($node->textContent, $text) === false) + continue; + $stack[] = $node; + } + $this->elements = $stack; + break; + case 'not': + $selector = self::unQuote($args); + $this->elements = $this->not($selector)->stack(); + break; + case 'slice': + // TODO jQuery difference ? + $args = explode(',', + str_replace(', ', ',', trim($args, "\"'")) + ); + $start = $args[0]; + $end = isset($args[1]) + ? $args[1] + : null; + if ($end > 0) + $end = $end-$start; + $this->elements = array_slice($this->elements, $start, $end); + break; + case 'has': + $selector = trim($args, "\"'"); + $stack = array(); + foreach($this->stack(1) as $el) { + if ($this->find($selector, $el, true)->length) + $stack[] = $el; + } + $this->elements = $stack; + break; + case 'submit': + case 'reset': + $this->elements = phpQuery::merge( + $this->map(array($this, 'is'), + "input[type=$class]", new CallbackParam() + ), + $this->map(array($this, 'is'), + "button[type=$class]", new CallbackParam() + ) + ); + break; +// $stack = array(); +// foreach($this->elements as $node) +// if ($node->is('input[type=submit]') || $node->is('button[type=submit]')) +// $stack[] = $el; +// $this->elements = $stack; + case 'input': + $this->elements = $this->map( + array($this, 'is'), + 'input', new CallbackParam() + )->elements; + break; + case 'password': + case 'checkbox': + case 'radio': + case 'hidden': + case 'image': + case 'file': + $this->elements = $this->map( + array($this, 'is'), + "input[type=$class]", new CallbackParam() + )->elements; + break; + case 'parent': + $this->elements = $this->map( + create_function('$node', ' + return $node instanceof DOMELEMENT && $node->childNodes->length + ? $node : null;') + )->elements; + break; + case 'empty': + $this->elements = $this->map( + create_function('$node', ' + return $node instanceof DOMELEMENT && $node->childNodes->length + ? null : $node;') + )->elements; + break; + case 'disabled': + case 'selected': + case 'checked': + $this->elements = $this->map( + array($this, 'is'), + "[$class]", new CallbackParam() + )->elements; + break; + case 'enabled': + $this->elements = $this->map( + create_function('$node', ' + return pq($node)->not(":disabled") ? $node : null;') + )->elements; + break; + case 'header': + $this->elements = $this->map( + create_function('$node', + '$isHeader = isset($node->tagName) && in_array($node->tagName, array( + "h1", "h2", "h3", "h4", "h5", "h6", "h7" + )); + return $isHeader + ? $node + : null;') + )->elements; +// $this->elements = $this->map( +// create_function('$node', '$node = pq($node); +// return $node->is("h1") +// || $node->is("h2") +// || $node->is("h3") +// || $node->is("h4") +// || $node->is("h5") +// || $node->is("h6") +// || $node->is("h7") +// ? $node +// : null;') +// )->elements; + break; + case 'only-child': + $this->elements = $this->map( + create_function('$node', + 'return pq($node)->siblings()->size() == 0 ? $node : null;') + )->elements; + break; + case 'first-child': + $this->elements = $this->map( + create_function('$node', 'return pq($node)->prevAll()->size() == 0 ? $node : null;') + )->elements; + break; + case 'last-child': + $this->elements = $this->map( + create_function('$node', 'return pq($node)->nextAll()->size() == 0 ? $node : null;') + )->elements; + break; + case 'nth-child': + $param = trim($args, "\"'"); + if (! $param) + break; + // nth-child(n+b) to nth-child(1n+b) + if ($param{0} == 'n') + $param = '1'.$param; + // :nth-child(index/even/odd/equation) + if ($param == 'even' || $param == 'odd') + $mapped = $this->map( + create_function('$node, $param', + '$index = pq($node)->prevAll()->size()+1; + if ($param == "even" && ($index%2) == 0) + return $node; + else if ($param == "odd" && $index%2 == 1) + return $node; + else + return null;'), + new CallbackParam(), $param + ); + else if (mb_strlen($param) > 1 && $param{1} == 'n') + // an+b + $mapped = $this->map( + create_function('$node, $param', + '$prevs = pq($node)->prevAll()->size(); + $index = 1+$prevs; + $b = mb_strlen($param) > 3 + ? $param{3} + : 0; + $a = $param{0}; + if ($b && $param{2} == "-") + $b = -$b; + if ($a > 0) { + return ($index-$b)%$a == 0 + ? $node + : null; + phpQuery::debug($a."*".floor($index/$a)."+$b-1 == ".($a*floor($index/$a)+$b-1)." ?= $prevs"); + return $a*floor($index/$a)+$b-1 == $prevs + ? $node + : null; + } else if ($a == 0) + return $index == $b + ? $node + : null; + else + // negative value + return $index <= $b + ? $node + : null; +// if (! $b) +// return $index%$a == 0 +// ? $node +// : null; +// else +// return ($index-$b)%$a == 0 +// ? $node +// : null; + '), + new CallbackParam(), $param + ); + else + // index + $mapped = $this->map( + create_function('$node, $index', + '$prevs = pq($node)->prevAll()->size(); + if ($prevs && $prevs == $index-1) + return $node; + else if (! $prevs && $index == 1) + return $node; + else + return null;'), + new CallbackParam(), $param + ); + $this->elements = $mapped->elements; + break; + default: + $this->debug("Unknown pseudoclass '{$class}', skipping..."); + } + } + /** + * @access private + */ + protected function __pseudoClassParam($paramsString) { + // TODO; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function is($selector, $nodes = null) { + phpQuery::debug(array("Is:", $selector)); + if (! $selector) + return false; + $oldStack = $this->elements; + $returnArray = false; + if ($nodes && is_array($nodes)) { + $this->elements = $nodes; + } else if ($nodes) + $this->elements = array($nodes); + $this->filter($selector, true); + $stack = $this->elements; + $this->elements = $oldStack; + if ($nodes) + return $stack ? $stack : null; + return (bool)count($stack); + } + /** + * Enter description here... + * jQuery difference. + * + * Callback: + * - $index int + * - $node DOMNode + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @link http://docs.jquery.com/Traversing/filter + */ + public function filterCallback($callback, $_skipHistory = false) { + if (! $_skipHistory) { + $this->elementsBackup = $this->elements; + $this->debug("Filtering by callback"); + } + $newStack = array(); + foreach($this->elements as $index => $node) { + $result = phpQuery::callbackRun($callback, array($index, $node)); + if (is_null($result) || (! is_null($result) && $result)) + $newStack[] = $node; + } + $this->elements = $newStack; + return $_skipHistory + ? $this + : $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @link http://docs.jquery.com/Traversing/filter + */ + public function filter($selectors, $_skipHistory = false) { + if ($selectors instanceof Callback OR $selectors instanceof Closure) + return $this->filterCallback($selectors, $_skipHistory); + if (! $_skipHistory) + $this->elementsBackup = $this->elements; + $notSimpleSelector = array(' ', '>', '~', '+', '/'); + if (! is_array($selectors)) + $selectors = $this->parseSelector($selectors); + if (! $_skipHistory) + $this->debug(array("Filtering:", $selectors)); + $finalStack = array(); + foreach($selectors as $selector) { + $stack = array(); + if (! $selector) + break; + // avoid first space or / + if (in_array($selector[0], $notSimpleSelector)) + $selector = array_slice($selector, 1); + // PER NODE selector chunks + foreach($this->stack() as $node) { + $break = false; + foreach($selector as $s) { + if (!($node instanceof DOMELEMENT)) { + // all besides DOMElement + if ( $s[0] == '[') { + $attr = trim($s, '[]'); + if ( mb_strpos($attr, '=')) { + list( $attr, $val ) = explode('=', $attr); + if ($attr == 'nodeType' && $node->nodeType != $val) + $break = true; + } + } else + $break = true; + } else { + // DOMElement only + // ID + if ( $s[0] == '#') { + if ( $node->getAttribute('id') != substr($s, 1) ) + $break = true; + // CLASSES + } else if ( $s[0] == '.') { + if (! $this->matchClasses( $s, $node ) ) + $break = true; + // ATTRS + } else if ( $s[0] == '[') { + // strip side brackets + $attr = trim($s, '[]'); + if (mb_strpos($attr, '=')) { + list($attr, $val) = explode('=', $attr); + $val = self::unQuote($val); + if ($attr == 'nodeType') { + if ($val != $node->nodeType) + $break = true; + } else if ($this->isRegexp($attr)) { + $val = extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? quotemeta(trim($val, '"\'')) + : preg_quote(trim($val, '"\''), '@'); + // switch last character + switch( substr($attr, -1)) { + // quotemeta used insted of preg_quote + // http://code.google.com/p/phpquery/issues/detail?id=76 + case '^': + $pattern = '^'.$val; + break; + case '*': + $pattern = '.*'.$val.'.*'; + break; + case '$': + $pattern = '.*'.$val.'$'; + break; + } + // cut last character + $attr = substr($attr, 0, -1); + $isMatch = extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? mb_ereg_match($pattern, $node->getAttribute($attr)) + : preg_match("@{$pattern}@", $node->getAttribute($attr)); + if (! $isMatch) + $break = true; + } else if ($node->getAttribute($attr) != $val) + $break = true; + } else if (! $node->hasAttribute($attr)) + $break = true; + // PSEUDO CLASSES + } else if ( $s[0] == ':') { + // skip + // TAG + } else if (trim($s)) { + if ($s != '*') { + // TODO namespaces + if (isset($node->tagName)) { + if ($node->tagName != $s) + $break = true; + } else if ($s == 'html' && ! $this->isRoot($node)) + $break = true; + } + // AVOID NON-SIMPLE SELECTORS + } else if (in_array($s, $notSimpleSelector)) { + $break = true; + $this->debug(array('Skipping non simple selector', $selector)); + } + } + if ($break) + break; + } + // if element passed all chunks of selector - add it to new stack + if (! $break ) + $stack[] = $node; + } + $tmpStack = $this->elements; + $this->elements = $stack; + // PER ALL NODES selector chunks + foreach($selector as $s) + // PSEUDO CLASSES + if ($s[0] == ':') + $this->pseudoClasses($s); + foreach($this->elements as $node) + // XXX it should be merged without duplicates + // but jQuery doesnt do that + $finalStack[] = $node; + $this->elements = $tmpStack; + } + $this->elements = $finalStack; + if ($_skipHistory) { + return $this; + } else { + $this->debug("Stack length after filter(): ".count($finalStack)); + return $this->newInstance(); + } + } + /** + * + * @param $value + * @return unknown_type + * @TODO implement in all methods using passed parameters + */ + protected static function unQuote($value) { + return $value[0] == '\'' || $value[0] == '"' + ? substr($value, 1, -1) + : $value; + } + /** + * Enter description here... + * + * @link http://docs.jquery.com/Ajax/load + * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo Support $selector + */ + public function load($url, $data = null, $callback = null) { + if ($data && ! is_array($data)) { + $callback = $data; + $data = null; + } + if (mb_strpos($url, ' ') !== false) { + $matches = null; + if (extension_loaded('mbstring') && phpQuery::$mbstringSupport) + mb_ereg('^([^ ]+) (.*)$', $url, $matches); + else + preg_match('^([^ ]+) (.*)$', $url, $matches); + $url = $matches[1]; + $selector = $matches[2]; + // FIXME this sucks, pass as callback param + $this->_loadSelector = $selector; + } + $ajax = array( + 'url' => $url, + 'type' => $data ? 'POST' : 'GET', + 'data' => $data, + 'complete' => $callback, + 'success' => array($this, '__loadSuccess') + ); + phpQuery::ajax($ajax); + return $this; + } + /** + * @access private + * @param $html + * @return unknown_type + */ + public function __loadSuccess($html) { + if ($this->_loadSelector) { + $html = phpQuery::newDocument($html)->find($this->_loadSelector); + unset($this->_loadSelector); + } + foreach($this->stack(1) as $node) { + phpQuery::pq($node, $this->getDocumentID()) + ->markup($html); + } + } + /** + * Enter description here... + * + * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo + */ + public function css() { + // TODO + return $this; + } + /** + * @todo + * + */ + public function show(){ + // TODO + return $this; + } + /** + * @todo + * + */ + public function hide(){ + // TODO + return $this; + } + /** + * Trigger a type of event on every matched element. + * + * @param unknown_type $type + * @param unknown_type $data + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO support more than event in $type (space-separated) + */ + public function trigger($type, $data = array()) { + foreach($this->elements as $node) + phpQueryEvents::trigger($this->getDocumentID(), $type, $data, $node); + return $this; + } + /** + * This particular method triggers all bound event handlers on an element (for a specific event type) WITHOUT executing the browsers default actions. + * + * @param unknown_type $type + * @param unknown_type $data + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO + */ + public function triggerHandler($type, $data = array()) { + // TODO; + } + /** + * Binds a handler to one or more events (like click) for each matched element. + * Can also bind custom events. + * + * @param unknown_type $type + * @param unknown_type $data Optional + * @param unknown_type $callback + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO support '!' (exclusive) events + * @TODO support more than event in $type (space-separated) + */ + public function bind($type, $data, $callback = null) { + // TODO check if $data is callable, not using is_callable + if (! isset($callback)) { + $callback = $data; + $data = null; + } + foreach($this->elements as $node) + phpQueryEvents::add($this->getDocumentID(), $node, $type, $data, $callback); + return $this; + } + /** + * Enter description here... + * + * @param unknown_type $type + * @param unknown_type $callback + * @return unknown + * @TODO namespace events + * @TODO support more than event in $type (space-separated) + */ + public function unbind($type = null, $callback = null) { + foreach($this->elements as $node) + phpQueryEvents::remove($this->getDocumentID(), $node, $type, $callback); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function change($callback = null) { + if ($callback) + return $this->bind('change', $callback); + return $this->trigger('change'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function submit($callback = null) { + if ($callback) + return $this->bind('submit', $callback); + return $this->trigger('submit'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function click($callback = null) { + if ($callback) + return $this->bind('click', $callback); + return $this->trigger('click'); + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapAllOld($wrapper) { + $wrapper = pq($wrapper)->_clone(); + if (! $wrapper->length() || ! $this->length() ) + return $this; + $wrapper->insertBefore($this->elements[0]); + $deepest = $wrapper->elements[0]; + while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT) + $deepest = $deepest->firstChild; + pq($deepest)->append($this); + return $this; + } + /** + * Enter description here... + * + * TODO testme... + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapAll($wrapper) { + if (! $this->length()) + return $this; + return phpQuery::pq($wrapper, $this->getDocumentID()) + ->clone() + ->insertBefore($this->get(0)) + ->map(array($this, '___wrapAllCallback')) + ->append($this); + } + /** + * + * @param $node + * @return unknown_type + * @access private + */ + public function ___wrapAllCallback($node) { + $deepest = $node; + while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT) + $deepest = $deepest->firstChild; + return $deepest; + } + /** + * Enter description here... + * NON JQUERY METHOD + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapAllPHP($codeBefore, $codeAfter) { + return $this + ->slice(0, 1) + ->beforePHP($codeBefore) + ->end() + ->slice(-1) + ->afterPHP($codeAfter) + ->end(); + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrap($wrapper) { + foreach($this->stack() as $node) + phpQuery::pq($node, $this->getDocumentID())->wrapAll($wrapper); + return $this; + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapPHP($codeBefore, $codeAfter) { + foreach($this->stack() as $node) + phpQuery::pq($node, $this->getDocumentID())->wrapAllPHP($codeBefore, $codeAfter); + return $this; + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapInner($wrapper) { + foreach($this->stack() as $node) + phpQuery::pq($node, $this->getDocumentID())->contents()->wrapAll($wrapper); + return $this; + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapInnerPHP($codeBefore, $codeAfter) { + foreach($this->stack(1) as $node) + phpQuery::pq($node, $this->getDocumentID())->contents() + ->wrapAllPHP($codeBefore, $codeAfter); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @testme Support for text nodes + */ + public function contents() { + $stack = array(); + foreach($this->stack(1) as $el) { + // FIXME (fixed) http://code.google.com/p/phpquery/issues/detail?id=56 +// if (! isset($el->childNodes)) +// continue; + foreach($el->childNodes as $node) { + $stack[] = $node; + } + } + return $this->newInstance($stack); + } + /** + * Enter description here... + * + * jQuery difference. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function contentsUnwrap() { + foreach($this->stack(1) as $node) { + if (! $node->parentNode ) + continue; + $childNodes = array(); + // any modification in DOM tree breaks childNodes iteration, so cache them first + foreach($node->childNodes as $chNode ) + $childNodes[] = $chNode; + foreach($childNodes as $chNode ) +// $node->parentNode->appendChild($chNode); + $node->parentNode->insertBefore($chNode, $node); + $node->parentNode->removeChild($node); + } + return $this; + } + /** + * Enter description here... + * + * jQuery difference. + */ + public function switchWith($markup) { + $markup = pq($markup, $this->getDocumentID()); + $content = null; + foreach($this->stack(1) as $node) { + pq($node) + ->contents()->toReference($content)->end() + ->replaceWith($markup->clone()->append($content)); + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function eq($num) { + $oldStack = $this->elements; + $this->elementsBackup = $this->elements; + $this->elements = array(); + if ( isset($oldStack[$num]) ) + $this->elements[] = $oldStack[$num]; + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function size() { + return count($this->elements); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @deprecated Use length as attribute + */ + public function length() { + return $this->size(); + } + public function count() { + return $this->size(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo $level + */ + public function end($level = 1) { +// $this->elements = array_pop( $this->history ); +// return $this; +// $this->previous->DOM = $this->DOM; +// $this->previous->XPath = $this->XPath; + return $this->previous + ? $this->previous + : $this; + } + /** + * Enter description here... + * Normal use ->clone() . + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _clone() { + $newStack = array(); + //pr(array('copy... ', $this->whois())); + //$this->dumpHistory('copy'); + $this->elementsBackup = $this->elements; + foreach($this->elements as $node) { + $newStack[] = $node->cloneNode(true); + } + $this->elements = $newStack; + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function replaceWithPHP($code) { + return $this->replaceWith(phpQuery::php($code)); + } + /** + * Enter description here... + * + * @param String|phpQuery $content + * @link http://docs.jquery.com/Manipulation/replaceWith#content + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function replaceWith($content) { + return $this->after($content)->remove(); + } + /** + * Enter description here... + * + * @param String $selector + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo this works ? + */ + public function replaceAll($selector) { + foreach(phpQuery::pq($selector, $this->getDocumentID()) as $node) + phpQuery::pq($node, $this->getDocumentID()) + ->after($this->_clone()) + ->remove(); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function remove($selector = null) { + $loop = $selector + ? $this->filter($selector)->elements + : $this->elements; + foreach($loop as $node) { + if (! $node->parentNode ) + continue; + if (isset($node->tagName)) + $this->debug("Removing '{$node->tagName}'"); + $node->parentNode->removeChild($node); + // Mutation event + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'DOMNodeRemoved' + )); + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $node + ); + } + return $this; + } + protected function markupEvents($newMarkup, $oldMarkup, $node) { + if ($node->tagName == 'textarea' && $newMarkup != $oldMarkup) { + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'change' + )); + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $node + ); + } + } + /** + * jQuey difference + * + * @param $markup + * @return unknown_type + * @TODO trigger change event for textarea + */ + public function markup($markup = null, $callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + if ($this->documentWrapper->isXML) + return call_user_func_array(array($this, 'xml'), $args); + else + return call_user_func_array(array($this, 'html'), $args); + } + /** + * jQuey difference + * + * @param $markup + * @return unknown_type + */ + public function markupOuter($callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + if ($this->documentWrapper->isXML) + return call_user_func_array(array($this, 'xmlOuter'), $args); + else + return call_user_func_array(array($this, 'htmlOuter'), $args); + } + /** + * Enter description here... + * + * @param unknown_type $html + * @return string|phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO force html result + */ + public function html($html = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if (isset($html)) { + // INSERT + $nodes = $this->documentWrapper->import($html); + $this->empty(); + foreach($this->stack(1) as $alreadyAdded => $node) { + // for now, limit events for textarea + if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea') + $oldHtml = pq($node, $this->getDocumentID())->markup(); + foreach($nodes as $newNode) { + $node->appendChild($alreadyAdded + ? $newNode->cloneNode(true) + : $newNode + ); + } + // for now, limit events for textarea + if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea') + $this->markupEvents($html, $oldHtml, $node); + } + return $this; + } else { + // FETCH + $return = $this->documentWrapper->markup($this->elements, true); + $args = func_get_args(); + foreach(array_slice($args, 1) as $callback) { + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + } + /** + * @TODO force xml result + */ + public function xml($xml = null, $callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + return call_user_func_array(array($this, 'html'), $args); + } + /** + * Enter description here... + * @TODO force html result + * + * @return String + */ + public function htmlOuter($callback1 = null, $callback2 = null, $callback3 = null) { + $markup = $this->documentWrapper->markup($this->elements); + // pass thou callbacks + $args = func_get_args(); + foreach($args as $callback) { + $markup = phpQuery::callbackRun($callback, array($markup)); + } + return $markup; + } + /** + * @TODO force xml result + */ + public function xmlOuter($callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + return call_user_func_array(array($this, 'htmlOuter'), $args); + } + public function __toString() { + return $this->markupOuter(); + } + /** + * Just like html(), but returns markup with VALID (dangerous) PHP tags. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo support returning markup with PHP tags when called without param + */ + public function php($code = null) { + return $this->markupPHP($code); + } + /** + * Enter description here... + * + * @param $code + * @return unknown_type + */ + public function markupPHP($code = null) { + return isset($code) + ? $this->markup(phpQuery::php($code)) + : phpQuery::markupToPHP($this->markup()); + } + /** + * Enter description here... + * + * @param $code + * @return unknown_type + */ + public function markupOuterPHP() { + return phpQuery::markupToPHP($this->markupOuter()); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function children($selector = null) { + $stack = array(); + foreach($this->stack(1) as $node) { +// foreach($node->getElementsByTagName('*') as $newNode) { + foreach($node->childNodes as $newNode) { + if ($newNode->nodeType != 1) + continue; + if ($selector && ! $this->is($selector, $newNode)) + continue; + if ($this->elementsContainsNode($newNode, $stack)) + continue; + $stack[] = $newNode; + } + } + $this->elementsBackup = $this->elements; + $this->elements = $stack; + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function ancestors($selector = null) { + return $this->children( $selector ); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function append( $content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function appendPHP( $content) { + return $this->insert("", 'append'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function appendTo( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prepend( $content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @todo accept many arguments, which are joined, arrays maybe also + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prependPHP( $content) { + return $this->insert("", 'prepend'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prependTo( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function before($content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function beforePHP( $content) { + return $this->insert("", 'before'); + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function insertBefore( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function after( $content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function afterPHP( $content) { + return $this->insert("", 'after'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function insertAfter( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Internal insert method. Don't use it. + * + * @param unknown_type $target + * @param unknown_type $type + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function insert($target, $type) { + $this->debug("Inserting data with '{$type}'"); + $to = false; + switch( $type) { + case 'appendTo': + case 'prependTo': + case 'insertBefore': + case 'insertAfter': + $to = true; + } + switch(gettype($target)) { + case 'string': + $insertFrom = $insertTo = array(); + if ($to) { + // INSERT TO + $insertFrom = $this->elements; + if (phpQuery::isMarkup($target)) { + // $target is new markup, import it + $insertTo = $this->documentWrapper->import($target); + // insert into selected element + } else { + // $tagret is a selector + $thisStack = $this->elements; + $this->toRoot(); + $insertTo = $this->find($target)->elements; + $this->elements = $thisStack; + } + } else { + // INSERT FROM + $insertTo = $this->elements; + $insertFrom = $this->documentWrapper->import($target); + } + break; + case 'object': + $insertFrom = $insertTo = array(); + // phpQuery + if ($target instanceof self) { + if ($to) { + $insertTo = $target->elements; + if ($this->documentFragment && $this->stackIsRoot()) + // get all body children +// $loop = $this->find('body > *')->elements; + // TODO test it, test it hard... +// $loop = $this->newInstance($this->root)->find('> *')->elements; + $loop = $this->root->childNodes; + else + $loop = $this->elements; + // import nodes if needed + $insertFrom = $this->getDocumentID() == $target->getDocumentID() + ? $loop + : $target->documentWrapper->import($loop); + } else { + $insertTo = $this->elements; + if ( $target->documentFragment && $target->stackIsRoot() ) + // get all body children +// $loop = $target->find('body > *')->elements; + $loop = $target->root->childNodes; + else + $loop = $target->elements; + // import nodes if needed + $insertFrom = $this->getDocumentID() == $target->getDocumentID() + ? $loop + : $this->documentWrapper->import($loop); + } + // DOMNODE + } elseif ($target instanceof DOMNODE) { + // import node if needed +// if ( $target->ownerDocument != $this->DOM ) +// $target = $this->DOM->importNode($target, true); + if ( $to) { + $insertTo = array($target); + if ($this->documentFragment && $this->stackIsRoot()) + // get all body children + $loop = $this->root->childNodes; +// $loop = $this->find('body > *')->elements; + else + $loop = $this->elements; + foreach($loop as $fromNode) + // import nodes if needed + $insertFrom[] = ! $fromNode->ownerDocument->isSameNode($target->ownerDocument) + ? $target->ownerDocument->importNode($fromNode, true) + : $fromNode; + } else { + // import node if needed + if (! $target->ownerDocument->isSameNode($this->document)) + $target = $this->document->importNode($target, true); + $insertTo = $this->elements; + $insertFrom[] = $target; + } + } + break; + } + phpQuery::debug("From ".count($insertFrom)."; To ".count($insertTo)." nodes"); + foreach($insertTo as $insertNumber => $toNode) { + // we need static relative elements in some cases + switch( $type) { + case 'prependTo': + case 'prepend': + $firstChild = $toNode->firstChild; + break; + case 'insertAfter': + case 'after': + $nextSibling = $toNode->nextSibling; + break; + } + foreach($insertFrom as $fromNode) { + // clone if inserted already before + $insert = $insertNumber + ? $fromNode->cloneNode(true) + : $fromNode; + switch($type) { + case 'appendTo': + case 'append': +// $toNode->insertBefore( +// $fromNode, +// $toNode->lastChild->nextSibling +// ); + $toNode->appendChild($insert); + $eventTarget = $insert; + break; + case 'prependTo': + case 'prepend': + $toNode->insertBefore( + $insert, + $firstChild + ); + break; + case 'insertBefore': + case 'before': + if (! $toNode->parentNode) + throw new Exception("No parentNode, can't do {$type}()"); + else + $toNode->parentNode->insertBefore( + $insert, + $toNode + ); + break; + case 'insertAfter': + case 'after': + if (! $toNode->parentNode) + throw new Exception("No parentNode, can't do {$type}()"); + else + $toNode->parentNode->insertBefore( + $insert, + $nextSibling + ); + break; + } + // Mutation event + $event = new DOMEvent(array( + 'target' => $insert, + 'type' => 'DOMNodeInserted' + )); + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $insert + ); + } + } + return $this; + } + /** + * Enter description here... + * + * @return Int + */ + public function index($subject) { + $index = -1; + $subject = $subject instanceof phpQueryObject + ? $subject->elements[0] + : $subject; + foreach($this->newInstance() as $k => $node) { + if ($node->isSameNode($subject)) + $index = $k; + } + return $index; + } + /** + * Enter description here... + * + * @param unknown_type $start + * @param unknown_type $end + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @testme + */ + public function slice($start, $end = null) { +// $last = count($this->elements)-1; +// $end = $end +// ? min($end, $last) +// : $last; +// if ($start < 0) +// $start = $last+$start; +// if ($start > $last) +// return array(); + if ($end > 0) + $end = $end-$start; + return $this->newInstance( + array_slice($this->elements, $start, $end) + ); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function reverse() { + $this->elementsBackup = $this->elements; + $this->elements = array_reverse($this->elements); + return $this->newInstance(); + } + /** + * Return joined text content. + * @return String + */ + public function text($text = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if (isset($text)) + return $this->html(htmlspecialchars($text)); + $args = func_get_args(); + $args = array_slice($args, 1); + $return = ''; + foreach($this->elements as $node) { + $text = $node->textContent; + if (count($this->elements) > 1 && $text) + $text .= "\n"; + foreach($args as $callback) { + $text = phpQuery::callbackRun($callback, array($text)); + } + $return .= $text; + } + return $return; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function plugin($class, $file = null) { + phpQuery::plugin($class, $file); + return $this; + } + /** + * Deprecated, use $pq->plugin() instead. + * + * @deprecated + * @param $class + * @param $file + * @return unknown_type + */ + public static function extend($class, $file = null) { + return $this->plugin($class, $file); + } + /** + * + * @access private + * @param $method + * @param $args + * @return unknown_type + */ + public function __call($method, $args) { + $aliasMethods = array('clone', 'empty'); + if (isset(phpQuery::$extendMethods[$method])) { + array_unshift($args, $this); + return phpQuery::callbackRun( + phpQuery::$extendMethods[$method], $args + ); + } else if (isset(phpQuery::$pluginsMethods[$method])) { + array_unshift($args, $this); + $class = phpQuery::$pluginsMethods[$method]; + $realClass = "phpQueryObjectPlugin_$class"; + $return = call_user_func_array( + array($realClass, $method), + $args + ); + // XXX deprecate ? + return is_null($return) + ? $this + : $return; + } else if (in_array($method, $aliasMethods)) { + return call_user_func_array(array($this, '_'.$method), $args); + } else + throw new Exception("Method '{$method}' doesnt exist"); + } + /** + * Safe rename of next(). + * + * Use it ONLY when need to call next() on an iterated object (in same time). + * Normaly there is no need to do such thing ;) + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _next($selector = null) { + return $this->newInstance( + $this->getElementSiblings('nextSibling', $selector, true) + ); + } + /** + * Use prev() and next(). + * + * @deprecated + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _prev($selector = null) { + return $this->prev($selector); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prev($selector = null) { + return $this->newInstance( + $this->getElementSiblings('previousSibling', $selector, true) + ); + } + /** + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo + */ + public function prevAll($selector = null) { + return $this->newInstance( + $this->getElementSiblings('previousSibling', $selector) + ); + } + /** + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo FIXME: returns source elements insted of next siblings + */ + public function nextAll($selector = null) { + return $this->newInstance( + $this->getElementSiblings('nextSibling', $selector) + ); + } + /** + * @access private + */ + protected function getElementSiblings($direction, $selector = null, $limitToOne = false) { + $stack = array(); + $count = 0; + foreach($this->stack() as $node) { + $test = $node; + while( isset($test->{$direction}) && $test->{$direction}) { + $test = $test->{$direction}; + if (! $test instanceof DOMELEMENT) + continue; + $stack[] = $test; + if ($limitToOne) + break; + } + } + if ($selector) { + $stackOld = $this->elements; + $this->elements = $stack; + $stack = $this->filter($selector, true)->stack(); + $this->elements = $stackOld; + } + return $stack; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function siblings($selector = null) { + $stack = array(); + $siblings = array_merge( + $this->getElementSiblings('previousSibling', $selector), + $this->getElementSiblings('nextSibling', $selector) + ); + foreach($siblings as $node) { + if (! $this->elementsContainsNode($node, $stack)) + $stack[] = $node; + } + return $this->newInstance($stack); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function not($selector = null) { + if (is_string($selector)) + phpQuery::debug(array('not', $selector)); + else + phpQuery::debug('not'); + $stack = array(); + if ($selector instanceof self || $selector instanceof DOMNODE) { + foreach($this->stack() as $node) { + if ($selector instanceof self) { + $matchFound = false; + foreach($selector->stack() as $notNode) { + if ($notNode->isSameNode($node)) + $matchFound = true; + } + if (! $matchFound) + $stack[] = $node; + } else if ($selector instanceof DOMNODE) { + if (! $selector->isSameNode($node)) + $stack[] = $node; + } else { + if (! $this->is($selector)) + $stack[] = $node; + } + } + } else { + $orgStack = $this->stack(); + $matched = $this->filter($selector, true)->stack(); +// $matched = array(); +// // simulate OR in filter() instead of AND 5y +// foreach($this->parseSelector($selector) as $s) { +// $matched = array_merge($matched, +// $this->filter(array($s))->stack() +// ); +// } + foreach($orgStack as $node) + if (! $this->elementsContainsNode($node, $matched)) + $stack[] = $node; + } + return $this->newInstance($stack); + } + /** + * Enter description here... + * + * @param string|phpQueryObject + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function add($selector = null) { + if (! $selector) + return $this; + $stack = array(); + $this->elementsBackup = $this->elements; + $found = phpQuery::pq($selector, $this->getDocumentID()); + $this->merge($found->elements); + return $this->newInstance(); + } + /** + * @access private + */ + protected function merge() { + foreach(func_get_args() as $nodes) + foreach($nodes as $newNode ) + if (! $this->elementsContainsNode($newNode) ) + $this->elements[] = $newNode; + } + /** + * @access private + * TODO refactor to stackContainsNode + */ + protected function elementsContainsNode($nodeToCheck, $elementsStack = null) { + $loop = ! is_null($elementsStack) + ? $elementsStack + : $this->elements; + foreach($loop as $node) { + if ( $node->isSameNode( $nodeToCheck ) ) + return true; + } + return false; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function parent($selector = null) { + $stack = array(); + foreach($this->elements as $node ) + if ( $node->parentNode && ! $this->elementsContainsNode($node->parentNode, $stack) ) + $stack[] = $node->parentNode; + $this->elementsBackup = $this->elements; + $this->elements = $stack; + if ( $selector ) + $this->filter($selector, true); + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function parents($selector = null) { + $stack = array(); + if (! $this->elements ) + $this->debug('parents() - stack empty'); + foreach($this->elements as $node) { + $test = $node; + while( $test->parentNode) { + $test = $test->parentNode; + if ($this->isRoot($test)) + break; + if (! $this->elementsContainsNode($test, $stack)) { + $stack[] = $test; + continue; + } + } + } + $this->elementsBackup = $this->elements; + $this->elements = $stack; + if ( $selector ) + $this->filter($selector, true); + return $this->newInstance(); + } + /** + * Internal stack iterator. + * + * @access private + */ + public function stack($nodeTypes = null) { + if (!isset($nodeTypes)) + return $this->elements; + if (!is_array($nodeTypes)) + $nodeTypes = array($nodeTypes); + $return = array(); + foreach($this->elements as $node) { + if (in_array($node->nodeType, $nodeTypes)) + $return[] = $node; + } + return $return; + } + // TODO phpdoc; $oldAttr is result of hasAttribute, before any changes + protected function attrEvents($attr, $oldAttr, $oldValue, $node) { + // skip events for XML documents + if (! $this->isXHTML() && ! $this->isHTML()) + return; + $event = null; + // identify + $isInputValue = $node->tagName == 'input' + && ( + in_array($node->getAttribute('type'), + array('text', 'password', 'hidden')) + || !$node->getAttribute('type') + ); + $isRadio = $node->tagName == 'input' + && $node->getAttribute('type') == 'radio'; + $isCheckbox = $node->tagName == 'input' + && $node->getAttribute('type') == 'checkbox'; + $isOption = $node->tagName == 'option'; + if ($isInputValue && $attr == 'value' && $oldValue != $node->getAttribute($attr)) { + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'change' + )); + } else if (($isRadio || $isCheckbox) && $attr == 'checked' && ( + // check + (! $oldAttr && $node->hasAttribute($attr)) + // un-check + || (! $node->hasAttribute($attr) && $oldAttr) + )) { + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'change' + )); + } else if ($isOption && $node->parentNode && $attr == 'selected' && ( + // select + (! $oldAttr && $node->hasAttribute($attr)) + // un-select + || (! $node->hasAttribute($attr) && $oldAttr) + )) { + $event = new DOMEvent(array( + 'target' => $node->parentNode, + 'type' => 'change' + )); + } + if ($event) { + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $node + ); + } + } + public function attr($attr = null, $value = null) { + foreach($this->stack(1) as $node) { + if (! is_null($value)) { + $loop = $attr == '*' + ? $this->getNodeAttrs($node) + : array($attr); + foreach($loop as $a) { + $oldValue = $node->getAttribute($a); + $oldAttr = $node->hasAttribute($a); + // TODO raises an error when charset other than UTF-8 + // while document's charset is also not UTF-8 + @$node->setAttribute($a, $value); + $this->attrEvents($a, $oldAttr, $oldValue, $node); + } + } else if ($attr == '*') { + // jQuery difference + $return = array(); + foreach($node->attributes as $n => $v) + $return[$n] = $v->value; + return $return; + } else + return $node->hasAttribute($attr) + ? $node->getAttribute($attr) + : null; + } + return is_null($value) + ? '' : $this; + } + /** + * @access private + */ + protected function getNodeAttrs($node) { + $return = array(); + foreach($node->attributes as $n => $o) + $return[] = $n; + return $return; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo check CDATA ??? + */ + public function attrPHP($attr, $code) { + if (! is_null($code)) { + $value = '<'.'?php '.$code.' ?'.'>'; + // TODO tempolary solution + // http://code.google.com/p/phpquery/issues/detail?id=17 +// if (function_exists('mb_detect_encoding') && mb_detect_encoding($value) == 'ASCII') +// $value = mb_convert_encoding($value, 'UTF-8', 'HTML-ENTITIES'); + } + foreach($this->stack(1) as $node) { + if (! is_null($code)) { +// $attrNode = $this->DOM->createAttribute($attr); + $node->setAttribute($attr, $value); +// $attrNode->value = $value; +// $node->appendChild($attrNode); + } else if ( $attr == '*') { + // jQuery diff + $return = array(); + foreach($node->attributes as $n => $v) + $return[$n] = $v->value; + return $return; + } else + return $node->getAttribute($attr); + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function removeAttr($attr) { + foreach($this->stack(1) as $node) { + $loop = $attr == '*' + ? $this->getNodeAttrs($node) + : array($attr); + foreach($loop as $a) { + $oldValue = $node->getAttribute($a); + $node->removeAttribute($a); + $this->attrEvents($a, $oldValue, null, $node); + } + } + return $this; + } + /** + * Return form element value. + * + * @return String Fields value. + */ + public function val($val = null) { + if (! isset($val)) { + if ($this->eq(0)->is('select')) { + $selected = $this->eq(0)->find('option[selected=selected]'); + if ($selected->is('[value]')) + return $selected->attr('value'); + else + return $selected->text(); + } else if ($this->eq(0)->is('textarea')) + return $this->eq(0)->markup(); + else + return $this->eq(0)->attr('value'); + } else { + $_val = null; + foreach($this->stack(1) as $node) { + $node = pq($node, $this->getDocumentID()); + if (is_array($val) && in_array($node->attr('type'), array('checkbox', 'radio'))) { + $isChecked = in_array($node->attr('value'), $val) + || in_array($node->attr('name'), $val); + if ($isChecked) + $node->attr('checked', 'checked'); + else + $node->removeAttr('checked'); + } else if ($node->get(0)->tagName == 'select') { + if (! isset($_val)) { + $_val = array(); + if (! is_array($val)) + $_val = array((string)$val); + else + foreach($val as $v) + $_val[] = $v; + } + foreach($node['option']->stack(1) as $option) { + $option = pq($option, $this->getDocumentID()); + $selected = false; + // XXX: workaround for string comparsion, see issue #96 + // http://code.google.com/p/phpquery/issues/detail?id=96 + $selected = is_null($option->attr('value')) + ? in_array($option->markup(), $_val) + : in_array($option->attr('value'), $_val); +// $optionValue = $option->attr('value'); +// $optionText = $option->text(); +// $optionTextLenght = mb_strlen($optionText); +// foreach($_val as $v) +// if ($optionValue == $v) +// $selected = true; +// else if ($optionText == $v && $optionTextLenght == mb_strlen($v)) +// $selected = true; + if ($selected) + $option->attr('selected', 'selected'); + else + $option->removeAttr('selected'); + } + } else if ($node->get(0)->tagName == 'textarea') + $node->markup($val); + else + $node->attr('value', $val); + } + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function andSelf() { + if ( $this->previous ) + $this->elements = array_merge($this->elements, $this->previous->elements); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function addClass( $className) { + if (! $className) + return $this; + foreach($this->stack(1) as $node) { + if (! $this->is(".$className", $node)) + $node->setAttribute( + 'class', + trim($node->getAttribute('class').' '.$className) + ); + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function addClassPHP( $className) { + foreach($this->stack(1) as $node) { + $classes = $node->getAttribute('class'); + $newValue = $classes + ? $classes.' <'.'?php '.$className.' ?'.'>' + : '<'.'?php '.$className.' ?'.'>'; + $node->setAttribute('class', $newValue); + } + return $this; + } + /** + * Enter description here... + * + * @param string $className + * @return bool + */ + public function hasClass($className) { + foreach($this->stack(1) as $node) { + if ( $this->is(".$className", $node)) + return true; + } + return false; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function removeClass($className) { + foreach($this->stack(1) as $node) { + $classes = explode( ' ', $node->getAttribute('class')); + if ( in_array($className, $classes)) { + $classes = array_diff($classes, array($className)); + if ( $classes ) + $node->setAttribute('class', implode(' ', $classes)); + else + $node->removeAttribute('class'); + } + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function toggleClass($className) { + foreach($this->stack(1) as $node) { + if ( $this->is( $node, '.'.$className )) + $this->removeClass($className); + else + $this->addClass($className); + } + return $this; + } + /** + * Proper name without underscore (just ->empty()) also works. + * + * Removes all child nodes from the set of matched elements. + * + * Example: + * pq("p")._empty() + * + * HTML: + *

Hello, Person and person

+ * + * Result: + * [

] + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _empty() { + foreach($this->stack(1) as $node) { + // thx to 'dave at dgx dot cz' + $node->nodeValue = ''; + } + return $this; + } + /** + * Enter description here... + * + * @param array|string $callback Expects $node as first param, $index as second + * @param array $scope External variables passed to callback. Use compact('varName1', 'varName2'...) and extract($scope) + * @param array $arg1 Will ba passed as third and futher args to callback. + * @param array $arg2 Will ba passed as fourth and futher args to callback, and so on... + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function each($callback, $param1 = null, $param2 = null, $param3 = null) { + $paramStructure = null; + if (func_num_args() > 1) { + $paramStructure = func_get_args(); + $paramStructure = array_slice($paramStructure, 1); + } + foreach($this->elements as $v) + phpQuery::callbackRun($callback, array($v), $paramStructure); + return $this; + } + /** + * Run callback on actual object. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function callback($callback, $param1 = null, $param2 = null, $param3 = null) { + $params = func_get_args(); + $params[0] = $this; + phpQuery::callbackRun($callback, $params); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo add $scope and $args as in each() ??? + */ + public function map($callback, $param1 = null, $param2 = null, $param3 = null) { +// $stack = array(); +//// foreach($this->newInstance() as $node) { +// foreach($this->newInstance() as $node) { +// $result = call_user_func($callback, $node); +// if ($result) +// $stack[] = $result; +// } + $params = func_get_args(); + array_unshift($params, $this->elements); + return $this->newInstance( + call_user_func_array(array('phpQuery', 'map'), $params) +// phpQuery::map($this->elements, $callback) + ); + } + /** + * Enter description here... + * + * @param $key + * @param $value + */ + public function data($key, $value = null) { + if (! isset($value)) { + // TODO? implement specific jQuery behavior od returning parent values + // is child which we look up doesn't exist + return phpQuery::data($this->get(0), $key, $value, $this->getDocumentID()); + } else { + foreach($this as $node) + phpQuery::data($node, $key, $value, $this->getDocumentID()); + return $this; + } + } + /** + * Enter description here... + * + * @param $key + */ + public function removeData($key) { + foreach($this as $node) + phpQuery::removeData($node, $key, $this->getDocumentID()); + return $this; + } + // INTERFACE IMPLEMENTATIONS + + // ITERATOR INTERFACE + /** + * @access private + */ + public function rewind(){ + $this->debug('iterating foreach'); +// phpQuery::selectDocument($this->getDocumentID()); + $this->elementsBackup = $this->elements; + $this->elementsInterator = $this->elements; + $this->valid = isset( $this->elements[0] ) + ? 1 : 0; +// $this->elements = $this->valid +// ? array($this->elements[0]) +// : array(); + $this->current = 0; + } + /** + * @access private + */ + public function current(){ + return $this->elementsInterator[ $this->current ]; + } + /** + * @access private + */ + public function key(){ + return $this->current; + } + /** + * Double-function method. + * + * First: main iterator interface method. + * Second: Returning next sibling, alias for _next(). + * + * Proper functionality is choosed automagicaly. + * + * @see phpQueryObject::_next() + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function next($cssSelector = null){ +// if ($cssSelector || $this->valid) +// return $this->_next($cssSelector); + $this->valid = isset( $this->elementsInterator[ $this->current+1 ] ) + ? true + : false; + if (! $this->valid && $this->elementsInterator) { + $this->elementsInterator = null; + } else if ($this->valid) { + $this->current++; + } else { + return $this->_next($cssSelector); + } + } + /** + * @access private + */ + public function valid(){ + return $this->valid; + } + // ITERATOR INTERFACE END + // ARRAYACCESS INTERFACE + /** + * @access private + */ + public function offsetExists($offset) { + return $this->find($offset)->size() > 0; + } + /** + * @access private + */ + public function offsetGet($offset) { + return $this->find($offset); + } + /** + * @access private + */ + public function offsetSet($offset, $value) { +// $this->find($offset)->replaceWith($value); + $this->find($offset)->html($value); + } + /** + * @access private + */ + public function offsetUnset($offset) { + // empty + throw new Exception("Can't do unset, use array interface only for calling queries and replacing HTML."); + } + // ARRAYACCESS INTERFACE END + /** + * Returns node's XPath. + * + * @param unknown_type $oneNode + * @return string + * @TODO use native getNodePath is avaible + * @access private + */ + protected function getNodeXpath($oneNode = null, $namespace = null) { + $return = array(); + $loop = $oneNode + ? array($oneNode) + : $this->elements; +// if ($namespace) +// $namespace .= ':'; + foreach($loop as $node) { + if ($node instanceof DOMDOCUMENT) { + $return[] = ''; + continue; + } + $xpath = array(); + while(! ($node instanceof DOMDOCUMENT)) { + $i = 1; + $sibling = $node; + while($sibling->previousSibling) { + $sibling = $sibling->previousSibling; + $isElement = $sibling instanceof DOMELEMENT; + if ($isElement && $sibling->tagName == $node->tagName) + $i++; + } + $xpath[] = $this->isXML() + ? "*[local-name()='{$node->tagName}'][{$i}]" + : "{$node->tagName}[{$i}]"; + $node = $node->parentNode; + } + $xpath = join('/', array_reverse($xpath)); + $return[] = '/'.$xpath; + } + return $oneNode + ? $return[0] + : $return; + } + // HELPERS + public function whois($oneNode = null) { + $return = array(); + $loop = $oneNode + ? array( $oneNode ) + : $this->elements; + foreach($loop as $node) { + if (isset($node->tagName)) { + $tag = in_array($node->tagName, array('php', 'js')) + ? strtoupper($node->tagName) + : $node->tagName; + $return[] = $tag + .($node->getAttribute('id') + ? '#'.$node->getAttribute('id'):'') + .($node->getAttribute('class') + ? '.'.join('.', split(' ', $node->getAttribute('class'))):'') + .($node->getAttribute('name') + ? '[name="'.$node->getAttribute('name').'"]':'') + .($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') === false + ? '[value="'.substr(str_replace("\n", '', $node->getAttribute('value')), 0, 15).'"]':'') + .($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') !== false + ? '[value=PHP]':'') + .($node->getAttribute('selected') + ? '[selected]':'') + .($node->getAttribute('checked') + ? '[checked]':'') + ; + } else if ($node instanceof DOMTEXT) { + if (trim($node->textContent)) + $return[] = 'Text:'.substr(str_replace("\n", ' ', $node->textContent), 0, 15); + } else { + + } + } + return $oneNode && isset($return[0]) + ? $return[0] + : $return; + } + /** + * Dump htmlOuter and preserve chain. Usefull for debugging. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * + */ + public function dump() { + print 'DUMP #'.(phpQuery::$dumpCount++).' '; + $debug = phpQuery::$debug; + phpQuery::$debug = false; +// print __FILE__.':'.__LINE__."\n"; + var_dump($this->htmlOuter()); + return $this; + } + public function dumpWhois() { + print 'DUMP #'.(phpQuery::$dumpCount++).' '; + $debug = phpQuery::$debug; + phpQuery::$debug = false; +// print __FILE__.':'.__LINE__."\n"; + var_dump('whois', $this->whois()); + phpQuery::$debug = $debug; + return $this; + } + public function dumpLength() { + print 'DUMP #'.(phpQuery::$dumpCount++).' '; + $debug = phpQuery::$debug; + phpQuery::$debug = false; +// print __FILE__.':'.__LINE__."\n"; + var_dump('length', $this->length()); + phpQuery::$debug = $debug; + return $this; + } + public function dumpTree($html = true, $title = true) { + $output = $title + ? 'DUMP #'.(phpQuery::$dumpCount++)." \n" : ''; + $debug = phpQuery::$debug; + phpQuery::$debug = false; + foreach($this->stack() as $node) + $output .= $this->__dumpTree($node); + phpQuery::$debug = $debug; + print $html + ? nl2br(str_replace(' ', ' ', $output)) + : $output; + return $this; + } + private function __dumpTree($node, $intend = 0) { + $whois = $this->whois($node); + $return = ''; + if ($whois) + $return .= str_repeat(' - ', $intend).$whois."\n"; + if (isset($node->childNodes)) + foreach($node->childNodes as $chNode) + $return .= $this->__dumpTree($chNode, $intend+1); + return $return; + } + /** + * Dump htmlOuter and stop script execution. Usefull for debugging. + * + */ + public function dumpDie() { + print __FILE__.':'.__LINE__; + var_dump($this->htmlOuter()); + die(); + } +} + + +// -- Multibyte Compatibility functions --------------------------------------- +// http://svn.iphonewebdev.com/lace/lib/mb_compat.php + +/** + * mb_internal_encoding() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_internal_encoding')) +{ + function mb_internal_encoding($enc) {return true; } +} + +/** + * mb_regex_encoding() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_regex_encoding')) +{ + function mb_regex_encoding($enc) {return true; } +} + +/** + * mb_strlen() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_strlen')) +{ + function mb_strlen($str) + { + return strlen($str); + } +} + +/** + * mb_strpos() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_strpos')) +{ + function mb_strpos($haystack, $needle, $offset=0) + { + return strpos($haystack, $needle, $offset); + } +} +/** + * mb_stripos() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_stripos')) +{ + function mb_stripos($haystack, $needle, $offset=0) + { + return stripos($haystack, $needle, $offset); + } +} + +/** + * mb_substr() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_substr')) +{ + function mb_substr($str, $start, $length=0) + { + return substr($str, $start, $length); + } +} + +/** + * mb_substr_count() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_substr_count')) +{ + function mb_substr_count($haystack, $needle) + { + return substr_count($haystack, $needle); + } +} + + /** * Static namespace for phpQuery functions. * diff --git a/phpQuery/phpQuery/Callback.php b/phpQuery/phpQuery/Callback.php deleted file mode 100644 index d9a90ea..0000000 --- a/phpQuery/phpQuery/Callback.php +++ /dev/null @@ -1,152 +0,0 @@ - - * - * @TODO??? return fake forwarding function created via create_function - * @TODO honor paramStructure - */ -class Callback - implements ICallbackNamed { - public $callback = null; - public $params = null; - protected $name; - public function __construct($callback, $param1 = null, $param2 = null, - $param3 = null) { - $params = func_get_args(); - $params = array_slice($params, 1); - if ($callback instanceof Callback) { - // TODO implement recurention - } else { - $this->callback = $callback; - $this->params = $params; - } - } - public function getName() { - return 'Callback: '.$this->name; - } - public function hasName() { - return isset($this->name) && $this->name; - } - public function setName($name) { - $this->name = $name; - return $this; - } - // TODO test me -// public function addParams() { -// $params = func_get_args(); -// return new Callback($this->callback, $this->params+$params); -// } -} -/** - * Shorthand for new Callback(create_function(...), ...); - * - * @author Tobiasz Cudnik - */ -class CallbackBody extends Callback { - public function __construct($paramList, $code, $param1 = null, $param2 = null, - $param3 = null) { - $params = func_get_args(); - $params = array_slice($params, 2); - $this->callback = create_function($paramList, $code); - $this->params = $params; - } -} -/** - * Callback type which on execution returns reference passed during creation. - * - * @author Tobiasz Cudnik - */ -class CallbackReturnReference extends Callback - implements ICallbackNamed { - protected $reference; - public function __construct(&$reference, $name = null){ - $this->reference =& $reference; - $this->callback = array($this, 'callback'); - } - public function callback() { - return $this->reference; - } - public function getName() { - return 'Callback: '.$this->name; - } - public function hasName() { - return isset($this->name) && $this->name; - } -} -/** - * Callback type which on execution returns value passed during creation. - * - * @author Tobiasz Cudnik - */ -class CallbackReturnValue extends Callback - implements ICallbackNamed { - protected $value; - protected $name; - public function __construct($value, $name = null){ - $this->value =& $value; - $this->name = $name; - $this->callback = array($this, 'callback'); - } - public function callback() { - return $this->value; - } - public function __toString() { - return $this->getName(); - } - public function getName() { - return 'Callback: '.$this->name; - } - public function hasName() { - return isset($this->name) && $this->name; - } -} -/** - * CallbackParameterToReference can be used when we don't really want a callback, - * only parameter passed to it. CallbackParameterToReference takes first - * parameter's value and passes it to reference. - * - * @author Tobiasz Cudnik - */ -class CallbackParameterToReference extends Callback { - /** - * @param $reference - * @TODO implement $paramIndex; - * param index choose which callback param will be passed to reference - */ - public function __construct(&$reference){ - $this->callback =& $reference; - } -} -//class CallbackReference extends Callback { -// /** -// * -// * @param $reference -// * @param $paramIndex -// * @todo implement $paramIndex; param index choose which callback param will be passed to reference -// */ -// public function __construct(&$reference, $name = null){ -// $this->callback =& $reference; -// } -//} -class CallbackParam {} \ No newline at end of file diff --git a/phpQuery/phpQuery/DOMDocumentWrapper.php b/phpQuery/phpQuery/DOMDocumentWrapper.php deleted file mode 100644 index 0b6a7fd..0000000 --- a/phpQuery/phpQuery/DOMDocumentWrapper.php +++ /dev/null @@ -1,677 +0,0 @@ - changes to
- * - * @todo check XML catalogs compatibility - * @author Tobiasz Cudnik - * @package phpQuery - */ -class DOMDocumentWrapper { - /** - * @var DOMDocument - */ - public $document; - public $id; - /** - * @todo Rewrite as method and quess if null. - * @var unknown_type - */ - public $contentType = ''; - public $xpath; - public $uuid = 0; - public $data = array(); - public $dataNodes = array(); - public $events = array(); - public $eventsNodes = array(); - public $eventsGlobal = array(); - /** - * @TODO iframes support http://code.google.com/p/phpquery/issues/detail?id=28 - * @var unknown_type - */ - public $frames = array(); - /** - * Document root, by default equals to document itself. - * Used by documentFragments. - * - * @var DOMNode - */ - public $root; - public $isDocumentFragment; - public $isXML = false; - public $isXHTML = false; - public $isHTML = false; - public $charset; - public function __construct($markup = null, $contentType = null, $newDocumentID = null) { - if (isset($markup)) - $this->load($markup, $contentType, $newDocumentID); - $this->id = $newDocumentID - ? $newDocumentID - : md5(microtime()); - } - public function load($markup, $contentType = null, $newDocumentID = null) { -// phpQuery::$documents[$id] = $this; - $this->contentType = strtolower($contentType); - if ($markup instanceof DOMDOCUMENT) { - $this->document = $markup; - $this->root = $this->document; - $this->charset = $this->document->encoding; - // TODO isDocumentFragment - } else { - $loaded = $this->loadMarkup($markup); - } - if ($loaded) { -// $this->document->formatOutput = true; - $this->document->preserveWhiteSpace = true; - $this->xpath = new DOMXPath($this->document); - $this->afterMarkupLoad(); - return true; - // remember last loaded document -// return phpQuery::selectDocument($id); - } - return false; - } - protected function afterMarkupLoad() { - if ($this->isXHTML) { - $this->xpath->registerNamespace("html", "http://www.w3.org/1999/xhtml"); - } - } - protected function loadMarkup($markup) { - $loaded = false; - if ($this->contentType) { - self::debug("Load markup for content type {$this->contentType}"); - // content determined by contentType - list($contentType, $charset) = $this->contentTypeToArray($this->contentType); - switch($contentType) { - case 'text/html': - phpQuery::debug("Loading HTML, content type '{$this->contentType}'"); - $loaded = $this->loadMarkupHTML($markup, $charset); - break; - case 'text/xml': - case 'application/xhtml+xml': - phpQuery::debug("Loading XML, content type '{$this->contentType}'"); - $loaded = $this->loadMarkupXML($markup, $charset); - break; - default: - // for feeds or anything that sometimes doesn't use text/xml - if (strpos('xml', $this->contentType) !== false) { - phpQuery::debug("Loading XML, content type '{$this->contentType}'"); - $loaded = $this->loadMarkupXML($markup, $charset); - } else - phpQuery::debug("Could not determine document type from content type '{$this->contentType}'"); - } - } else { - // content type autodetection - if ($this->isXML($markup)) { - phpQuery::debug("Loading XML, isXML() == true"); - $loaded = $this->loadMarkupXML($markup); - if (! $loaded && $this->isXHTML) { - phpQuery::debug('Loading as XML failed, trying to load as HTML, isXHTML == true'); - $loaded = $this->loadMarkupHTML($markup); - } - } else { - phpQuery::debug("Loading HTML, isXML() == false"); - $loaded = $this->loadMarkupHTML($markup); - } - } - return $loaded; - } - protected function loadMarkupReset() { - $this->isXML = $this->isXHTML = $this->isHTML = false; - } - protected function documentCreate($charset, $version = '1.0') { - if (! $version) - $version = '1.0'; - $this->document = new DOMDocument($version, $charset); - $this->charset = $this->document->encoding; -// $this->document->encoding = $charset; - $this->document->formatOutput = true; - $this->document->preserveWhiteSpace = true; - } - protected function loadMarkupHTML($markup, $requestedCharset = null) { - if (phpQuery::$debug) - phpQuery::debug('Full markup load (HTML): '.substr($markup, 0, 250)); - $this->loadMarkupReset(); - $this->isHTML = true; - if (!isset($this->isDocumentFragment)) - $this->isDocumentFragment = self::isDocumentFragmentHTML($markup); - $charset = null; - $documentCharset = $this->charsetFromHTML($markup); - $addDocumentCharset = false; - if ($documentCharset) { - $charset = $documentCharset; - $markup = $this->charsetFixHTML($markup); - } else if ($requestedCharset) { - $charset = $requestedCharset; - } - if (! $charset) - $charset = phpQuery::$defaultCharset; - // HTTP 1.1 says that the default charset is ISO-8859-1 - // @see http://www.w3.org/International/O-HTTP-charset - if (! $documentCharset) { - $documentCharset = 'ISO-8859-1'; - $addDocumentCharset = true; - } - // Should be careful here, still need 'magic encoding detection' since lots of pages have other 'default encoding' - // Worse, some pages can have mixed encodings... we'll try not to worry about that - $requestedCharset = strtoupper($requestedCharset); - $documentCharset = strtoupper($documentCharset); - phpQuery::debug("DOC: $documentCharset REQ: $requestedCharset"); - if ($requestedCharset && $documentCharset && $requestedCharset !== $documentCharset) { - phpQuery::debug("CHARSET CONVERT"); - // Document Encoding Conversion - // http://code.google.com/p/phpquery/issues/detail?id=86 - if (function_exists('mb_detect_encoding')) { - $possibleCharsets = array($documentCharset, $requestedCharset, 'AUTO'); - $docEncoding = mb_detect_encoding($markup, implode(', ', $possibleCharsets)); - if (! $docEncoding) - $docEncoding = $documentCharset; // ok trust the document - phpQuery::debug("DETECTED '$docEncoding'"); - // Detected does not match what document says... - if ($docEncoding !== $documentCharset) { - // Tricky.. - } - if ($docEncoding !== $requestedCharset) { - phpQuery::debug("CONVERT $docEncoding => $requestedCharset"); - $markup = mb_convert_encoding($markup, $requestedCharset, $docEncoding); - $markup = $this->charsetAppendToHTML($markup, $requestedCharset); - $charset = $requestedCharset; - } - } else { - phpQuery::debug("TODO: charset conversion without mbstring..."); - } - } - $return = false; - if ($this->isDocumentFragment) { - phpQuery::debug("Full markup load (HTML), DocumentFragment detected, using charset '$charset'"); - $return = $this->documentFragmentLoadMarkup($this, $charset, $markup); - } else { - if ($addDocumentCharset) { - phpQuery::debug("Full markup load (HTML), appending charset: '$charset'"); - $markup = $this->charsetAppendToHTML($markup, $charset); - } - phpQuery::debug("Full markup load (HTML), documentCreate('$charset')"); - $this->documentCreate($charset); - $return = phpQuery::$debug === 2 - ? $this->document->loadHTML($markup) - : @$this->document->loadHTML($markup); - if ($return) - $this->root = $this->document; - } - if ($return && ! $this->contentType) - $this->contentType = 'text/html'; - return $return; - } - protected function loadMarkupXML($markup, $requestedCharset = null) { - if (phpQuery::$debug) - phpQuery::debug('Full markup load (XML): '.substr($markup, 0, 250)); - $this->loadMarkupReset(); - $this->isXML = true; - // check agains XHTML in contentType or markup - $isContentTypeXHTML = $this->isXHTML(); - $isMarkupXHTML = $this->isXHTML($markup); - if ($isContentTypeXHTML || $isMarkupXHTML) { - self::debug('Full markup load (XML), XHTML detected'); - $this->isXHTML = true; - } - // determine document fragment - if (! isset($this->isDocumentFragment)) - $this->isDocumentFragment = $this->isXHTML - ? self::isDocumentFragmentXHTML($markup) - : self::isDocumentFragmentXML($markup); - // this charset will be used - $charset = null; - // charset from XML declaration @var string - $documentCharset = $this->charsetFromXML($markup); - if (! $documentCharset) { - if ($this->isXHTML) { - // this is XHTML, try to get charset from content-type meta header - $documentCharset = $this->charsetFromHTML($markup); - if ($documentCharset) { - phpQuery::debug("Full markup load (XML), appending XHTML charset '$documentCharset'"); - $this->charsetAppendToXML($markup, $documentCharset); - $charset = $documentCharset; - } - } - if (! $documentCharset) { - // if still no document charset... - $charset = $requestedCharset; - } - } else if ($requestedCharset) { - $charset = $requestedCharset; - } - if (! $charset) { - $charset = phpQuery::$defaultCharset; - } - if ($requestedCharset && $documentCharset && $requestedCharset != $documentCharset) { - // TODO place for charset conversion -// $charset = $requestedCharset; - } - $return = false; - if ($this->isDocumentFragment) { - phpQuery::debug("Full markup load (XML), DocumentFragment detected, using charset '$charset'"); - $return = $this->documentFragmentLoadMarkup($this, $charset, $markup); - } else { - // FIXME ??? - if ($isContentTypeXHTML && ! $isMarkupXHTML) - if (! $documentCharset) { - phpQuery::debug("Full markup load (XML), appending charset '$charset'"); - $markup = $this->charsetAppendToXML($markup, $charset); - } - // see http://pl2.php.net/manual/en/book.dom.php#78929 - // LIBXML_DTDLOAD (>= PHP 5.1) - // does XML ctalogues works with LIBXML_NONET - // $this->document->resolveExternals = true; - // TODO test LIBXML_COMPACT for performance improvement - // create document - $this->documentCreate($charset); - if (phpversion() < 5.1) { - $this->document->resolveExternals = true; - $return = phpQuery::$debug === 2 - ? $this->document->loadXML($markup) - : @$this->document->loadXML($markup); - } else { - /** @link http://pl2.php.net/manual/en/libxml.constants.php */ - $libxmlStatic = phpQuery::$debug === 2 - ? LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET - : LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOERROR; - $return = $this->document->loadXML($markup, $libxmlStatic); -// if (! $return) -// $return = $this->document->loadHTML($markup); - } - if ($return) - $this->root = $this->document; - } - if ($return) { - if (! $this->contentType) { - if ($this->isXHTML) - $this->contentType = 'application/xhtml+xml'; - else - $this->contentType = 'text/xml'; - } - return $return; - } else { - throw new Exception("Error loading XML markup"); - } - } - protected function isXHTML($markup = null) { - if (! isset($markup)) { - return strpos($this->contentType, 'xhtml') !== false; - } - // XXX ok ? - return strpos($markup, "doctype) && is_object($dom->doctype) -// ? $dom->doctype->publicId -// : self::$defaultDoctype; - } - protected function isXML($markup) { -// return strpos($markup, ']+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', - $markup, $matches - ); - if (! isset($matches[0])) - return array(null, null); - // get attr 'content' - preg_match('@content\\s*=\\s*(["|\'])(.+?)\\1@', $matches[0], $matches); - if (! isset($matches[0])) - return array(null, null); - return $this->contentTypeToArray($matches[2]); - } - protected function charsetFromHTML($markup) { - $contentType = $this->contentTypeFromHTML($markup); - return $contentType[1]; - } - protected function charsetFromXML($markup) { - $matches; - // find declaration - preg_match('@<'.'?xml[^>]+encoding\\s*=\\s*(["|\'])(.*?)\\1@i', - $markup, $matches - ); - return isset($matches[2]) - ? strtolower($matches[2]) - : null; - } - /** - * Repositions meta[type=charset] at the start of head. Bypasses DOMDocument bug. - * - * @link http://code.google.com/p/phpquery/issues/detail?id=80 - * @param $html - */ - protected function charsetFixHTML($markup) { - $matches = array(); - // find meta tag - preg_match('@\s*]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', - $markup, $matches, PREG_OFFSET_CAPTURE - ); - if (! isset($matches[0])) - return; - $metaContentType = $matches[0][0]; - $markup = substr($markup, 0, $matches[0][1]) - .substr($markup, $matches[0][1]+strlen($metaContentType)); - $headStart = stripos($markup, ''); - $markup = substr($markup, 0, $headStart+6).$metaContentType - .substr($markup, $headStart+6); - return $markup; - } - protected function charsetAppendToHTML($html, $charset, $xhtml = false) { - // remove existing meta[type=content-type] - $html = preg_replace('@\s*]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', '', $html); - $meta = ''; - if (strpos($html, ')@s', - "{$meta}", - $html - ); - } - } else { - return preg_replace( - '@)@s', - ''.$meta, - $html - ); - } - } - protected function charsetAppendToXML($markup, $charset) { - $declaration = '<'.'?xml version="1.0" encoding="'.$charset.'"?'.'>'; - return $declaration.$markup; - } - public static function isDocumentFragmentHTML($markup) { - return stripos($markup, 'documentFragmentCreate($node, $sourceCharset); -// if ($fake === false) -// throw new Exception("Error loading documentFragment markup"); -// else -// $return = array_merge($return, -// $this->import($fake->root->childNodes) -// ); -// } else { -// $return[] = $this->document->importNode($node, true); -// } -// } -// return $return; -// } else { -// // string markup -// $fake = $this->documentFragmentCreate($source, $sourceCharset); -// if ($fake === false) -// throw new Exception("Error loading documentFragment markup"); -// else -// return $this->import($fake->root->childNodes); -// } - if (is_array($source) || $source instanceof DOMNODELIST) { - // dom nodes - self::debug('Importing nodes to document'); - foreach($source as $node) - $return[] = $this->document->importNode($node, true); - } else { - // string markup - $fake = $this->documentFragmentCreate($source, $sourceCharset); - if ($fake === false) - throw new Exception("Error loading documentFragment markup"); - else - return $this->import($fake->root->childNodes); - } - return $return; - } - /** - * Creates new document fragment. - * - * @param $source - * @return DOMDocumentWrapper - */ - protected function documentFragmentCreate($source, $charset = null) { - $fake = new DOMDocumentWrapper(); - $fake->contentType = $this->contentType; - $fake->isXML = $this->isXML; - $fake->isHTML = $this->isHTML; - $fake->isXHTML = $this->isXHTML; - $fake->root = $fake->document; - if (! $charset) - $charset = $this->charset; -// $fake->documentCreate($this->charset); - if ($source instanceof DOMNODE && !($source instanceof DOMNODELIST)) - $source = array($source); - if (is_array($source) || $source instanceof DOMNODELIST) { - // dom nodes - // load fake document - if (! $this->documentFragmentLoadMarkup($fake, $charset)) - return false; - $nodes = $fake->import($source); - foreach($nodes as $node) - $fake->root->appendChild($node); - } else { - // string markup - $this->documentFragmentLoadMarkup($fake, $charset, $source); - } - return $fake; - } - /** - * - * @param $document DOMDocumentWrapper - * @param $markup - * @return $document - */ - private function documentFragmentLoadMarkup($fragment, $charset, $markup = null) { - // TODO error handling - // TODO copy doctype - // tempolary turn off - $fragment->isDocumentFragment = false; - if ($fragment->isXML) { - if ($fragment->isXHTML) { - // add FAKE element to set default namespace - $fragment->loadMarkupXML('' - .'' - .''.$markup.''); - $fragment->root = $fragment->document->firstChild->nextSibling; - } else { - $fragment->loadMarkupXML(''.$markup.''); - $fragment->root = $fragment->document->firstChild; - } - } else { - $markup2 = phpQuery::$defaultDoctype.''; - $noBody = strpos($markup, 'loadMarkupHTML($markup2); - // TODO resolv body tag merging issue - $fragment->root = $noBody - ? $fragment->document->firstChild->nextSibling->firstChild->nextSibling - : $fragment->document->firstChild->nextSibling->firstChild->nextSibling; - } - if (! $fragment->root) - return false; - $fragment->isDocumentFragment = true; - return true; - } - protected function documentFragmentToMarkup($fragment) { - phpQuery::debug('documentFragmentToMarkup'); - $tmp = $fragment->isDocumentFragment; - $fragment->isDocumentFragment = false; - $markup = $fragment->markup(); - if ($fragment->isXML) { - $markup = substr($markup, 0, strrpos($markup, '')); - if ($fragment->isXHTML) { - $markup = substr($markup, strpos($markup, '')+6); - } - } else { - $markup = substr($markup, strpos($markup, '')+6); - $markup = substr($markup, 0, strrpos($markup, '')); - } - $fragment->isDocumentFragment = $tmp; - if (phpQuery::$debug) - phpQuery::debug('documentFragmentToMarkup: '.substr($markup, 0, 150)); - return $markup; - } - /** - * Return document markup, starting with optional $nodes as root. - * - * @param $nodes DOMNode|DOMNodeList - * @return string - */ - public function markup($nodes = null, $innerMarkup = false) { - if (isset($nodes) && count($nodes) == 1 && $nodes[0] instanceof DOMDOCUMENT) - $nodes = null; - if (isset($nodes)) { - $markup = ''; - if (!is_array($nodes) && !($nodes instanceof DOMNODELIST) ) - $nodes = array($nodes); - if ($this->isDocumentFragment && ! $innerMarkup) - foreach($nodes as $i => $node) - if ($node->isSameNode($this->root)) { - // var_dump($node); - $nodes = array_slice($nodes, 0, $i) - + phpQuery::DOMNodeListToArray($node->childNodes) - + array_slice($nodes, $i+1); - } - if ($this->isXML && ! $innerMarkup) { - self::debug("Getting outerXML with charset '{$this->charset}'"); - // we need outerXML, so we can benefit from - // $node param support in saveXML() - foreach($nodes as $node) - $markup .= $this->document->saveXML($node); - } else { - $loop = array(); - if ($innerMarkup) - foreach($nodes as $node) { - if ($node->childNodes) - foreach($node->childNodes as $child) - $loop[] = $child; - else - $loop[] = $node; - } - else - $loop = $nodes; - self::debug("Getting markup, moving selected nodes (".count($loop).") to new DocumentFragment"); - $fake = $this->documentFragmentCreate($loop); - $markup = $this->documentFragmentToMarkup($fake); - } - if ($this->isXHTML) { - self::debug("Fixing XHTML"); - $markup = self::markupFixXHTML($markup); - } - self::debug("Markup: ".substr($markup, 0, 250)); - return $markup; - } else { - if ($this->isDocumentFragment) { - // documentFragment, html only... - self::debug("Getting markup, DocumentFragment detected"); -// return $this->markup( -//// $this->document->getElementsByTagName('body')->item(0) -// $this->document->root, true -// ); - $markup = $this->documentFragmentToMarkup($this); - // no need for markupFixXHTML, as it's done thought markup($nodes) method - return $markup; - } else { - self::debug("Getting markup (".($this->isXML?'XML':'HTML')."), final with charset '{$this->charset}'"); - $markup = $this->isXML - ? $this->document->saveXML() - : $this->document->saveHTML(); - if ($this->isXHTML) { - self::debug("Fixing XHTML"); - $markup = self::markupFixXHTML($markup); - } - self::debug("Markup: ".substr($markup, 0, 250)); - return $markup; - } - } - } - protected static function markupFixXHTML($markup) { - $markup = self::expandEmptyTag('script', $markup); - $markup = self::expandEmptyTag('select', $markup); - $markup = self::expandEmptyTag('textarea', $markup); - return $markup; - } - public static function debug($text) { - phpQuery::debug($text); - } - /** - * expandEmptyTag - * - * @param $tag - * @param $xml - * @return unknown_type - * @author mjaque at ilkebenson dot com - * @link http://php.net/manual/en/domdocument.savehtml.php#81256 - */ - public static function expandEmptyTag($tag, $xml){ - $indice = 0; - while ($indice< strlen($xml)){ - $pos = strpos($xml, "<$tag ", $indice); - if ($pos){ - $posCierre = strpos($xml, ">", $pos); - if ($xml[$posCierre-1] == "/"){ - $xml = substr_replace($xml, ">", $posCierre-1, 2); - } - $indice = $posCierre; - } - else break; - } - return $xml; - } -} \ No newline at end of file diff --git a/phpQuery/phpQuery/DOMEvent.php b/phpQuery/phpQuery/DOMEvent.php deleted file mode 100644 index 0cb0c46..0000000 --- a/phpQuery/phpQuery/DOMEvent.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @package phpQuery - * @todo implement ArrayAccess ? - */ -class DOMEvent { - /** - * Returns a boolean indicating whether the event bubbles up through the DOM or not. - * - * @var unknown_type - */ - public $bubbles = true; - /** - * Returns a boolean indicating whether the event is cancelable. - * - * @var unknown_type - */ - public $cancelable = true; - /** - * Returns a reference to the currently registered target for the event. - * - * @var unknown_type - */ - public $currentTarget; - /** - * Returns detail about the event, depending on the type of event. - * - * @var unknown_type - * @link http://developer.mozilla.org/en/DOM/event.detail - */ - public $detail; // ??? - /** - * Used to indicate which phase of the event flow is currently being evaluated. - * - * NOT IMPLEMENTED - * - * @var unknown_type - * @link http://developer.mozilla.org/en/DOM/event.eventPhase - */ - public $eventPhase; // ??? - /** - * The explicit original target of the event (Mozilla-specific). - * - * NOT IMPLEMENTED - * - * @var unknown_type - */ - public $explicitOriginalTarget; // moz only - /** - * The original target of the event, before any retargetings (Mozilla-specific). - * - * NOT IMPLEMENTED - * - * @var unknown_type - */ - public $originalTarget; // moz only - /** - * Identifies a secondary target for the event. - * - * @var unknown_type - */ - public $relatedTarget; - /** - * Returns a reference to the target to which the event was originally dispatched. - * - * @var unknown_type - */ - public $target; - /** - * Returns the time that the event was created. - * - * @var unknown_type - */ - public $timeStamp; - /** - * Returns the name of the event (case-insensitive). - */ - public $type; - public $runDefault = true; - public $data = null; - public function __construct($data) { - foreach($data as $k => $v) { - $this->$k = $v; - } - if (! $this->timeStamp) - $this->timeStamp = time(); - } - /** - * Cancels the event (if it is cancelable). - * - */ - public function preventDefault() { - $this->runDefault = false; - } - /** - * Stops the propagation of events further along in the DOM. - * - */ - public function stopPropagation() { - $this->bubbles = false; - } -} diff --git a/phpQuery/phpQuery/Zend/Exception.php b/phpQuery/phpQuery/Zend/Exception.php deleted file mode 100644 index 599d8a0..0000000 --- a/phpQuery/phpQuery/Zend/Exception.php +++ /dev/null @@ -1,30 +0,0 @@ - 5, - 'strictredirects' => false, - 'useragent' => 'Zend_Http_Client', - 'timeout' => 10, - 'adapter' => 'Zend_Http_Client_Adapter_Socket', - 'httpversion' => self::HTTP_1, - 'keepalive' => false, - 'storeresponse' => true, - 'strict' => true - ); - - /** - * The adapter used to preform the actual connection to the server - * - * @var Zend_Http_Client_Adapter_Interface - */ - protected $adapter = null; - - /** - * Request URI - * - * @var Zend_Uri_Http - */ - protected $uri; - - /** - * Associative array of request headers - * - * @var array - */ - protected $headers = array(); - - /** - * HTTP request method - * - * @var string - */ - protected $method = self::GET; - - /** - * Associative array of GET parameters - * - * @var array - */ - protected $paramsGet = array(); - - /** - * Assiciative array of POST parameters - * - * @var array - */ - protected $paramsPost = array(); - - /** - * Request body content type (for POST requests) - * - * @var string - */ - protected $enctype = null; - - /** - * The raw post data to send. Could be set by setRawData($data, $enctype). - * - * @var string - */ - protected $raw_post_data = null; - - /** - * HTTP Authentication settings - * - * Expected to be an associative array with this structure: - * $this->auth = array('user' => 'username', 'password' => 'password', 'type' => 'basic') - * Where 'type' should be one of the supported authentication types (see the AUTH_* - * constants), for example 'basic' or 'digest'. - * - * If null, no authentication will be used. - * - * @var array|null - */ - protected $auth; - - /** - * File upload arrays (used in POST requests) - * - * An associative array, where each element is of the format: - * 'name' => array('filename.txt', 'text/plain', 'This is the actual file contents') - * - * @var array - */ - protected $files = array(); - - /** - * The client's cookie jar - * - * @var Zend_Http_CookieJar - */ - protected $cookiejar = null; - - /** - * The last HTTP request sent by the client, as string - * - * @var string - */ - protected $last_request = null; - - /** - * The last HTTP response received by the client - * - * @var Zend_Http_Response - */ - protected $last_response = null; - - /** - * Redirection counter - * - * @var int - */ - protected $redirectCounter = 0; - - /** - * Fileinfo magic database resource - * - * This varaiable is populated the first time _detectFileMimeType is called - * and is then reused on every call to this method - * - * @var resource - */ - static protected $_fileInfoDb = null; - - /** - * Contructor method. Will create a new HTTP client. Accepts the target - * URL and optionally configuration array. - * - * @param Zend_Uri_Http|string $uri - * @param array $config Configuration key-value pairs. - */ - public function __construct($uri = null, $config = null) - { - if ($uri !== null) $this->setUri($uri); - if ($config !== null) $this->setConfig($config); - } - - /** - * Set the URI for the next request - * - * @param Zend_Uri_Http|string $uri - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setUri($uri) - { - if (is_string($uri)) { - $uri = Zend_Uri::factory($uri); - } - - if (!$uri instanceof Zend_Uri_Http) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception('Passed parameter is not a valid HTTP URI.'); - } - - // We have no ports, set the defaults - if (! $uri->getPort()) { - $uri->setPort(($uri->getScheme() == 'https' ? 443 : 80)); - } - - $this->uri = $uri; - - return $this; - } - - /** - * Get the URI for the next request - * - * @param boolean $as_string If true, will return the URI as a string - * @return Zend_Uri_Http|string - */ - public function getUri($as_string = false) - { - if ($as_string && $this->uri instanceof Zend_Uri_Http) { - return $this->uri->__toString(); - } else { - return $this->uri; - } - } - - /** - * Set configuration parameters for this HTTP client - * - * @param array $config - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setConfig($config = array()) - { - if (! is_array($config)) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception('Expected array parameter, given ' . gettype($config)); - } - - foreach ($config as $k => $v) - $this->config[strtolower($k)] = $v; - - return $this; - } - - /** - * Set the next request's method - * - * Validated the passed method and sets it. If we have files set for - * POST requests, and the new method is not POST, the files are silently - * dropped. - * - * @param string $method - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setMethod($method = self::GET) - { - $regex = '/^[^\x00-\x1f\x7f-\xff\(\)<>@,;:\\\\"\/\[\]\?={}\s]+$/'; - if (! preg_match($regex, $method)) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("'{$method}' is not a valid HTTP request method."); - } - - if ($method == self::POST && $this->enctype === null) - $this->setEncType(self::ENC_URLENCODED); - - $this->method = $method; - - return $this; - } - - /** - * Set one or more request headers - * - * This function can be used in several ways to set the client's request - * headers: - * 1. By providing two parameters: $name as the header to set (eg. 'Host') - * and $value as it's value (eg. 'www.example.com'). - * 2. By providing a single header string as the only parameter - * eg. 'Host: www.example.com' - * 3. By providing an array of headers as the first parameter - * eg. array('host' => 'www.example.com', 'x-foo: bar'). In This case - * the function will call itself recursively for each array item. - * - * @param string|array $name Header name, full header string ('Header: value') - * or an array of headers - * @param mixed $value Header value or null - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setHeaders($name, $value = null) - { - // If we got an array, go recusive! - if (is_array($name)) { - foreach ($name as $k => $v) { - if (is_string($k)) { - $this->setHeaders($k, $v); - } else { - $this->setHeaders($v, null); - } - } - } else { - // Check if $name needs to be split - if ($value === null && (strpos($name, ':') > 0)) - list($name, $value) = explode(':', $name, 2); - - // Make sure the name is valid if we are in strict mode - if ($this->config['strict'] && (! preg_match('/^[a-zA-Z0-9-]+$/', $name))) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("{$name} is not a valid HTTP header name"); - } - - $normalized_name = strtolower($name); - - // If $value is null or false, unset the header - if ($value === null || $value === false) { - unset($this->headers[$normalized_name]); - - // Else, set the header - } else { - // Header names are storred lowercase internally. - if (is_string($value)) $value = trim($value); - $this->headers[$normalized_name] = array($name, $value); - } - } - - return $this; - } - - /** - * Get the value of a specific header - * - * Note that if the header has more than one value, an array - * will be returned. - * - * @param string $key - * @return string|array|null The header value or null if it is not set - */ - public function getHeader($key) - { - $key = strtolower($key); - if (isset($this->headers[$key])) { - return $this->headers[$key][1]; - } else { - return null; - } - } - - /** - * Set a GET parameter for the request. Wrapper around _setParameter - * - * @param string|array $name - * @param string $value - * @return Zend_Http_Client - */ - public function setParameterGet($name, $value = null) - { - if (is_array($name)) { - foreach ($name as $k => $v) - $this->_setParameter('GET', $k, $v); - } else { - $this->_setParameter('GET', $name, $value); - } - - return $this; - } - - /** - * Set a POST parameter for the request. Wrapper around _setParameter - * - * @param string|array $name - * @param string $value - * @return Zend_Http_Client - */ - public function setParameterPost($name, $value = null) - { - if (is_array($name)) { - foreach ($name as $k => $v) - $this->_setParameter('POST', $k, $v); - } else { - $this->_setParameter('POST', $name, $value); - } - - return $this; - } - - /** - * Set a GET or POST parameter - used by SetParameterGet and SetParameterPost - * - * @param string $type GET or POST - * @param string $name - * @param string $value - * @return null - */ - protected function _setParameter($type, $name, $value) - { - $parray = array(); - $type = strtolower($type); - switch ($type) { - case 'get': - $parray = &$this->paramsGet; - break; - case 'post': - $parray = &$this->paramsPost; - break; - } - - if ($value === null) { - if (isset($parray[$name])) unset($parray[$name]); - } else { - $parray[$name] = $value; - } - } - - /** - * Get the number of redirections done on the last request - * - * @return int - */ - public function getRedirectionsCount() - { - return $this->redirectCounter; - } - - /** - * Set HTTP authentication parameters - * - * $type should be one of the supported types - see the self::AUTH_* - * constants. - * - * To enable authentication: - * - * $this->setAuth('shahar', 'secret', Zend_Http_Client::AUTH_BASIC); - * - * - * To disable authentication: - * - * $this->setAuth(false); - * - * - * @see http://www.faqs.org/rfcs/rfc2617.html - * @param string|false $user User name or false disable authentication - * @param string $password Password - * @param string $type Authentication type - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setAuth($user, $password = '', $type = self::AUTH_BASIC) - { - // If we got false or null, disable authentication - if ($user === false || $user === null) { - $this->auth = null; - - // Else, set up authentication - } else { - // Check we got a proper authentication type - if (! defined('self::AUTH_' . strtoupper($type))) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("Invalid or not supported authentication type: '$type'"); - } - - $this->auth = array( - 'user' => (string) $user, - 'password' => (string) $password, - 'type' => $type - ); - } - - return $this; - } - - /** - * Set the HTTP client's cookie jar. - * - * A cookie jar is an object that holds and maintains cookies across HTTP requests - * and responses. - * - * @param Zend_Http_CookieJar|boolean $cookiejar Existing cookiejar object, true to create a new one, false to disable - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setCookieJar($cookiejar = true) - { - if (! class_exists('Zend_Http_CookieJar')) - require_once 'Zend/Http/CookieJar.php'; - - if ($cookiejar instanceof Zend_Http_CookieJar) { - $this->cookiejar = $cookiejar; - } elseif ($cookiejar === true) { - $this->cookiejar = new Zend_Http_CookieJar(); - } elseif (! $cookiejar) { - $this->cookiejar = null; - } else { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception('Invalid parameter type passed as CookieJar'); - } - - return $this; - } - - /** - * Return the current cookie jar or null if none. - * - * @return Zend_Http_CookieJar|null - */ - public function getCookieJar() - { - return $this->cookiejar; - } - - /** - * Add a cookie to the request. If the client has no Cookie Jar, the cookies - * will be added directly to the headers array as "Cookie" headers. - * - * @param Zend_Http_Cookie|string $cookie - * @param string|null $value If "cookie" is a string, this is the cookie value. - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setCookie($cookie, $value = null) - { - if (! class_exists('Zend_Http_Cookie')) - require_once 'Zend/Http/Cookie.php'; - - if (is_array($cookie)) { - foreach ($cookie as $c => $v) { - if (is_string($c)) { - $this->setCookie($c, $v); - } else { - $this->setCookie($v); - } - } - - return $this; - } - - if ($value !== null) $value = urlencode($value); - - if (isset($this->cookiejar)) { - if ($cookie instanceof Zend_Http_Cookie) { - $this->cookiejar->addCookie($cookie); - } elseif (is_string($cookie) && $value !== null) { - $cookie = Zend_Http_Cookie::fromString("{$cookie}={$value}", $this->uri); - $this->cookiejar->addCookie($cookie); - } - } else { - if ($cookie instanceof Zend_Http_Cookie) { - $name = $cookie->getName(); - $value = $cookie->getValue(); - $cookie = $name; - } - - if (preg_match("/[=,; \t\r\n\013\014]/", $cookie)) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("Cookie name cannot contain these characters: =,; \t\r\n\013\014 ({$cookie})"); - } - - $value = addslashes($value); - - if (! isset($this->headers['cookie'])) $this->headers['cookie'] = array('Cookie', ''); - $this->headers['cookie'][1] .= $cookie . '=' . $value . '; '; - } - - return $this; - } - - /** - * Set a file to upload (using a POST request) - * - * Can be used in two ways: - * - * 1. $data is null (default): $filename is treated as the name if a local file which - * will be read and sent. Will try to guess the content type using mime_content_type(). - * 2. $data is set - $filename is sent as the file name, but $data is sent as the file - * contents and no file is read from the file system. In this case, you need to - * manually set the content-type ($ctype) or it will default to - * application/octet-stream. - * - * @param string $filename Name of file to upload, or name to save as - * @param string $formname Name of form element to send as - * @param string $data Data to send (if null, $filename is read and sent) - * @param string $ctype Content type to use (if $data is set and $ctype is - * null, will be application/octet-stream) - * @return Zend_Http_Client - * @throws Zend_Http_Client_Exception - */ - public function setFileUpload($filename, $formname, $data = null, $ctype = null) - { - if ($data === null) { - if (($data = @file_get_contents($filename)) === false) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("Unable to read file '{$filename}' for upload"); - } - - if (! $ctype) $ctype = $this->_detectFileMimeType($filename); - } - - // Force enctype to multipart/form-data - $this->setEncType(self::ENC_FORMDATA); - - $this->files[$formname] = array(basename($filename), $ctype, $data); - - return $this; - } - - /** - * Set the encoding type for POST data - * - * @param string $enctype - * @return Zend_Http_Client - */ - public function setEncType($enctype = self::ENC_URLENCODED) - { - $this->enctype = $enctype; - - return $this; - } - - /** - * Set the raw (already encoded) POST data. - * - * This function is here for two reasons: - * 1. For advanced user who would like to set their own data, already encoded - * 2. For backwards compatibilty: If someone uses the old post($data) method. - * this method will be used to set the encoded data. - * - * @param string $data - * @param string $enctype - * @return Zend_Http_Client - */ - public function setRawData($data, $enctype = null) - { - $this->raw_post_data = $data; - $this->setEncType($enctype); - - return $this; - } - - /** - * Clear all GET and POST parameters - * - * Should be used to reset the request parameters if the client is - * used for several concurrent requests. - * - * @return Zend_Http_Client - */ - public function resetParameters() - { - // Reset parameter data - $this->paramsGet = array(); - $this->paramsPost = array(); - $this->files = array(); - $this->raw_post_data = null; - - // Clear outdated headers - if (isset($this->headers['content-type'])) unset($this->headers['content-type']); - if (isset($this->headers['content-length'])) unset($this->headers['content-length']); - - return $this; - } - - /** - * Get the last HTTP request as string - * - * @return string - */ - public function getLastRequest() - { - return $this->last_request; - } - - /** - * Get the last HTTP response received by this client - * - * If $config['storeresponse'] is set to false, or no response was - * stored yet, will return null - * - * @return Zend_Http_Response or null if none - */ - public function getLastResponse() - { - return $this->last_response; - } - - /** - * Load the connection adapter - * - * While this method is not called more than one for a client, it is - * seperated from ->request() to preserve logic and readability - * - * @param Zend_Http_Client_Adapter_Interface|string $adapter - * @return null - * @throws Zend_Http_Client_Exception - */ - public function setAdapter($adapter) - { - if (is_string($adapter)) { - try { - Zend_Loader::loadClass($adapter); - } catch (Zend_Exception $e) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("Unable to load adapter '$adapter': {$e->getMessage()}"); - } - - $adapter = new $adapter; - } - - if (! $adapter instanceof Zend_Http_Client_Adapter_Interface) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception('Passed adapter is not a HTTP connection adapter'); - } - - $this->adapter = $adapter; - $config = $this->config; - unset($config['adapter']); - $this->adapter->setConfig($config); - } - - /** - * Send the HTTP request and return an HTTP response object - * - * @param string $method - * @return Zend_Http_Response - * @throws Zend_Http_Client_Exception - */ - public function request($method = null) - { - if (! $this->uri instanceof Zend_Uri_Http) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception('No valid URI has been passed to the client'); - } - - if ($method) $this->setMethod($method); - $this->redirectCounter = 0; - $response = null; - - // Make sure the adapter is loaded - if ($this->adapter == null) $this->setAdapter($this->config['adapter']); - - // Send the first request. If redirected, continue. - do { - // Clone the URI and add the additional GET parameters to it - $uri = clone $this->uri; - if (! empty($this->paramsGet)) { - $query = $uri->getQuery(); - if (! empty($query)) $query .= '&'; - $query .= http_build_query($this->paramsGet, null, '&'); - - $uri->setQuery($query); - } - - $body = $this->_prepareBody(); - $headers = $this->_prepareHeaders(); - - // Open the connection, send the request and read the response - $this->adapter->connect($uri->getHost(), $uri->getPort(), - ($uri->getScheme() == 'https' ? true : false)); - - $this->last_request = $this->adapter->write($this->method, - $uri, $this->config['httpversion'], $headers, $body); - - $response = $this->adapter->read(); - if (! $response) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception('Unable to read response, or response is empty'); - } - - $response = Zend_Http_Response::fromString($response); - if ($this->config['storeresponse']) $this->last_response = $response; - - // Load cookies into cookie jar - if (isset($this->cookiejar)) $this->cookiejar->addCookiesFromResponse($response, $uri); - - // If we got redirected, look for the Location header - if ($response->isRedirect() && ($location = $response->getHeader('location'))) { - - // Check whether we send the exact same request again, or drop the parameters - // and send a GET request - if ($response->getStatus() == 303 || - ((! $this->config['strictredirects']) && ($response->getStatus() == 302 || - $response->getStatus() == 301))) { - - $this->resetParameters(); - $this->setMethod(self::GET); - } - - // If we got a well formed absolute URI - if (Zend_Uri_Http::check($location)) { - $this->setHeaders('host', null); - $this->setUri($location); - - } else { - - // Split into path and query and set the query - if (strpos($location, '?') !== false) { - list($location, $query) = explode('?', $location, 2); - } else { - $query = ''; - } - $this->uri->setQuery($query); - - // Else, if we got just an absolute path, set it - if(strpos($location, '/') === 0) { - $this->uri->setPath($location); - - // Else, assume we have a relative path - } else { - // Get the current path directory, removing any trailing slashes - $path = $this->uri->getPath(); - $path = rtrim(substr($path, 0, strrpos($path, '/')), "/"); - $this->uri->setPath($path . '/' . $location); - } - } - ++$this->redirectCounter; - - } else { - // If we didn't get any location, stop redirecting - break; - } - - } while ($this->redirectCounter < $this->config['maxredirects']); - - return $response; - } - - /** - * Prepare the request headers - * - * @return array - */ - protected function _prepareHeaders() - { - $headers = array(); - - // Set the host header - if (! isset($this->headers['host'])) { - $host = $this->uri->getHost(); - - // If the port is not default, add it - if (! (($this->uri->getScheme() == 'http' && $this->uri->getPort() == 80) || - ($this->uri->getScheme() == 'https' && $this->uri->getPort() == 443))) { - $host .= ':' . $this->uri->getPort(); - } - - $headers[] = "Host: {$host}"; - } - - // Set the connection header - if (! isset($this->headers['connection'])) { - if (! $this->config['keepalive']) $headers[] = "Connection: close"; - } - - // Set the Accept-encoding header if not set - depending on whether - // zlib is available or not. - if (! isset($this->headers['accept-encoding'])) { - if (function_exists('gzinflate')) { - $headers[] = 'Accept-encoding: gzip, deflate'; - } else { - $headers[] = 'Accept-encoding: identity'; - } - } - - // Set the content-type header - if ($this->method == self::POST && - (! isset($this->headers['content-type']) && isset($this->enctype))) { - - $headers[] = "Content-type: {$this->enctype}"; - } - - // Set the user agent header - if (! isset($this->headers['user-agent']) && isset($this->config['useragent'])) { - $headers[] = "User-agent: {$this->config['useragent']}"; - } - - // Set HTTP authentication if needed - if (is_array($this->auth)) { - $auth = self::encodeAuthHeader($this->auth['user'], $this->auth['password'], $this->auth['type']); - $headers[] = "Authorization: {$auth}"; - } - - // Load cookies from cookie jar - if (isset($this->cookiejar)) { - $cookstr = $this->cookiejar->getMatchingCookies($this->uri, - true, Zend_Http_CookieJar::COOKIE_STRING_CONCAT); - - if ($cookstr) $headers[] = "Cookie: {$cookstr}"; - } - - // Add all other user defined headers - foreach ($this->headers as $header) { - list($name, $value) = $header; - if (is_array($value)) - $value = implode(', ', $value); - - $headers[] = "$name: $value"; - } - - return $headers; - } - - /** - * Prepare the request body (for POST and PUT requests) - * - * @return string - * @throws Zend_Http_Client_Exception - */ - protected function _prepareBody() - { - // According to RFC2616, a TRACE request should not have a body. - if ($this->method == self::TRACE) { - return ''; - } - - // If we have raw_post_data set, just use it as the body. - if (isset($this->raw_post_data)) { - $this->setHeaders('Content-length', strlen($this->raw_post_data)); - return $this->raw_post_data; - } - - $body = ''; - - // If we have files to upload, force enctype to multipart/form-data - if (count ($this->files) > 0) $this->setEncType(self::ENC_FORMDATA); - - // If we have POST parameters or files, encode and add them to the body - if (count($this->paramsPost) > 0 || count($this->files) > 0) { - switch($this->enctype) { - case self::ENC_FORMDATA: - // Encode body as multipart/form-data - $boundary = '---ZENDHTTPCLIENT-' . md5(microtime()); - $this->setHeaders('Content-type', self::ENC_FORMDATA . "; boundary={$boundary}"); - - // Get POST parameters and encode them - $params = $this->_getParametersRecursive($this->paramsPost); - foreach ($params as $pp) { - $body .= self::encodeFormData($boundary, $pp[0], $pp[1]); - } - - // Encode files - foreach ($this->files as $name => $file) { - $fhead = array('Content-type' => $file[1]); - $body .= self::encodeFormData($boundary, $name, $file[2], $file[0], $fhead); - } - - $body .= "--{$boundary}--\r\n"; - break; - - case self::ENC_URLENCODED: - // Encode body as application/x-www-form-urlencoded - $this->setHeaders('Content-type', self::ENC_URLENCODED); - $body = http_build_query($this->paramsPost, '', '&'); - break; - - default: - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("Cannot handle content type '{$this->enctype}' automatically." . - " Please use Zend_Http_Client::setRawData to send this kind of content."); - break; - } - } - - // Set the content-length if we have a body or if request is POST/PUT - if ($body || $this->method == self::POST || $this->method == self::PUT) { - $this->setHeaders('Content-length', strlen($body)); - } - - return $body; - } - - /** - * Helper method that gets a possibly multi-level parameters array (get or - * post) and flattens it. - * - * The method returns an array of (key, value) pairs (because keys are not - * necessarily unique. If one of the parameters in as array, it will also - * add a [] suffix to the key. - * - * @param array $parray The parameters array - * @param bool $urlencode Whether to urlencode the name and value - * @return array - */ - protected function _getParametersRecursive($parray, $urlencode = false) - { - if (! is_array($parray)) return $parray; - $parameters = array(); - - foreach ($parray as $name => $value) { - if ($urlencode) $name = urlencode($name); - - // If $value is an array, iterate over it - if (is_array($value)) { - $name .= ($urlencode ? '%5B%5D' : '[]'); - foreach ($value as $subval) { - if ($urlencode) $subval = urlencode($subval); - $parameters[] = array($name, $subval); - } - } else { - if ($urlencode) $value = urlencode($value); - $parameters[] = array($name, $value); - } - } - - return $parameters; - } - - /** - * Attempt to detect the MIME type of a file using available extensions - * - * This method will try to detect the MIME type of a file. If the fileinfo - * extension is available, it will be used. If not, the mime_magic - * extension which is deprected but is still available in many PHP setups - * will be tried. - * - * If neither extension is available, the default application/octet-stream - * MIME type will be returned - * - * @param string $file File path - * @return string MIME type - */ - protected function _detectFileMimeType($file) - { - $type = null; - - // First try with fileinfo functions - if (function_exists('finfo_open')) { - if (self::$_fileInfoDb === null) { - self::$_fileInfoDb = @finfo_open(FILEINFO_MIME); - } - - if (self::$_fileInfoDb) { - $type = finfo_file(self::$_fileInfoDb, $file); - } - - } elseif (function_exists('mime_content_type')) { - $type = mime_content_type($file); - } - - // Fallback to the default application/octet-stream - if (! $type) { - $type = 'application/octet-stream'; - } - - return $type; - } - - /** - * Encode data to a multipart/form-data part suitable for a POST request. - * - * @param string $boundary - * @param string $name - * @param mixed $value - * @param string $filename - * @param array $headers Associative array of optional headers @example ("Content-transfer-encoding" => "binary") - * @return string - */ - public static function encodeFormData($boundary, $name, $value, $filename = null, $headers = array()) { - $ret = "--{$boundary}\r\n" . - 'Content-disposition: form-data; name="' . $name .'"'; - - if ($filename) $ret .= '; filename="' . $filename . '"'; - $ret .= "\r\n"; - - foreach ($headers as $hname => $hvalue) { - $ret .= "{$hname}: {$hvalue}\r\n"; - } - $ret .= "\r\n"; - - $ret .= "{$value}\r\n"; - - return $ret; - } - - /** - * Create a HTTP authentication "Authorization:" header according to the - * specified user, password and authentication method. - * - * @see http://www.faqs.org/rfcs/rfc2617.html - * @param string $user - * @param string $password - * @param string $type - * @return string - * @throws Zend_Http_Client_Exception - */ - public static function encodeAuthHeader($user, $password, $type = self::AUTH_BASIC) - { - $authHeader = null; - - switch ($type) { - case self::AUTH_BASIC: - // In basic authentication, the user name cannot contain ":" - if (strpos($user, ':') !== false) { - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("The user name cannot contain ':' in 'Basic' HTTP authentication"); - } - - $authHeader = 'Basic ' . base64_encode($user . ':' . $password); - break; - - //case self::AUTH_DIGEST: - /** - * @todo Implement digest authentication - */ - // break; - - default: - /** @see Zend_Http_Client_Exception */ - require_once 'Zend/Http/Client/Exception.php'; - throw new Zend_Http_Client_Exception("Not a supported HTTP authentication type: '$type'"); - } - - return $authHeader; - } -} diff --git a/phpQuery/phpQuery/Zend/Http/Client/Adapter/Exception.php b/phpQuery/phpQuery/Zend/Http/Client/Adapter/Exception.php deleted file mode 100644 index dfbe904..0000000 --- a/phpQuery/phpQuery/Zend/Http/Client/Adapter/Exception.php +++ /dev/null @@ -1,33 +0,0 @@ - 'ssl', - 'proxy_host' => '', - 'proxy_port' => 8080, - 'proxy_user' => '', - 'proxy_pass' => '', - 'proxy_auth' => Zend_Http_Client::AUTH_BASIC, - 'persistent' => false - ); - - /** - * Whether HTTPS CONNECT was already negotiated with the proxy or not - * - * @var boolean - */ - protected $negotiated = false; - - /** - * Connect to the remote server - * - * Will try to connect to the proxy server. If no proxy was set, will - * fall back to the target server (behave like regular Socket adapter) - * - * @param string $host - * @param int $port - * @param boolean $secure - * @param int $timeout - */ - public function connect($host, $port = 80, $secure = false) - { - // If no proxy is set, fall back to Socket adapter - if (! $this->config['proxy_host']) return parent::connect($host, $port, $secure); - - // Go through a proxy - the connection is actually to the proxy server - $host = $this->config['proxy_host']; - $port = $this->config['proxy_port']; - - // If we are connected to the wrong proxy, disconnect first - if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) { - if (is_resource($this->socket)) $this->close(); - } - - // Now, if we are not connected, connect - if (! is_resource($this->socket) || ! $this->config['keepalive']) { - $this->socket = @fsockopen($host, $port, $errno, $errstr, (int) $this->config['timeout']); - if (! $this->socket) { - $this->close(); - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception( - 'Unable to Connect to proxy server ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr); - } - - // Set the stream timeout - if (!stream_set_timeout($this->socket, (int) $this->config['timeout'])) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Unable to set the connection timeout'); - } - - // Update connected_to - $this->connected_to = array($host, $port); - } - } - - /** - * Send request to the proxy server - * - * @param string $method - * @param Zend_Uri_Http $uri - * @param string $http_ver - * @param array $headers - * @param string $body - * @return string Request as string - */ - public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') - { - // If no proxy is set, fall back to default Socket adapter - if (! $this->config['proxy_host']) return parent::write($method, $uri, $http_ver, $headers, $body); - - // Make sure we're properly connected - if (! $this->socket) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are not connected"); - } - - $host = $this->config['proxy_host']; - $port = $this->config['proxy_port']; - - if ($this->connected_to[0] != $host || $this->connected_to[1] != $port) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong proxy server"); - } - - // Add Proxy-Authorization header - if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) - $headers['proxy-authorization'] = Zend_Http_Client::encodeAuthHeader( - $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth'] - ); - - // if we are proxying HTTPS, preform CONNECT handshake with the proxy - if ($uri->getScheme() == 'https' && (! $this->negotiated)) { - $this->connectHandshake($uri->getHost(), $uri->getPort(), $http_ver, $headers); - $this->negotiated = true; - } - - // Save request method for later - $this->method = $method; - - // Build request headers - $request = "{$method} {$uri->__toString()} HTTP/{$http_ver}\r\n"; - - // Add all headers to the request string - foreach ($headers as $k => $v) { - if (is_string($k)) $v = "$k: $v"; - $request .= "$v\r\n"; - } - - // Add the request body - $request .= "\r\n" . $body; - - // Send the request - if (! @fwrite($this->socket, $request)) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception("Error writing request to proxy server"); - } - - return $request; - } - - /** - * Preform handshaking with HTTPS proxy using CONNECT method - * - * @param string $host - * @param integer $port - * @param string $http_ver - * @param array $headers - */ - protected function connectHandshake($host, $port = 443, $http_ver = '1.1', array &$headers = array()) - { - $request = "CONNECT $host:$port HTTP/$http_ver\r\n" . - "Host: " . $this->config['proxy_host'] . "\r\n"; - - // Add the user-agent header - if (isset($this->config['useragent'])) { - $request .= "User-agent: " . $this->config['useragent'] . "\r\n"; - } - - // If the proxy-authorization header is set, send it to proxy but remove - // it from headers sent to target host - if (isset($headers['proxy-authorization'])) { - $request .= "Proxy-authorization: " . $headers['proxy-authorization'] . "\r\n"; - unset($headers['proxy-authorization']); - } - - $request .= "\r\n"; - - // Send the request - if (! @fwrite($this->socket, $request)) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception("Error writing request to proxy server"); - } - - // Read response headers only - $response = ''; - $gotStatus = false; - while ($line = @fgets($this->socket)) { - $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); - if ($gotStatus) { - $response .= $line; - if (!chop($line)) break; - } - } - - // Check that the response from the proxy is 200 - if (Zend_Http_Response::extractCode($response) != 200) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception("Unable to connect to HTTPS proxy. Server response: " . $response); - } - - // If all is good, switch socket to secure mode. We have to fall back - // through the different modes - $modes = array( - STREAM_CRYPTO_METHOD_TLS_CLIENT, - STREAM_CRYPTO_METHOD_SSLv3_CLIENT, - STREAM_CRYPTO_METHOD_SSLv23_CLIENT, - STREAM_CRYPTO_METHOD_SSLv2_CLIENT - ); - - $success = false; - foreach($modes as $mode) { - $success = stream_socket_enable_crypto($this->socket, true, $mode); - if ($success) break; - } - - if (! $success) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception("Unable to connect to" . - " HTTPS server through proxy: could not negotiate secure connection."); - } - } - - /** - * Close the connection to the server - * - */ - public function close() - { - parent::close(); - $this->negotiated = false; - } - - /** - * Destructor: make sure the socket is disconnected - * - */ - public function __destruct() - { - if ($this->socket) $this->close(); - } -} diff --git a/phpQuery/phpQuery/Zend/Http/Client/Adapter/Socket.php b/phpQuery/phpQuery/Zend/Http/Client/Adapter/Socket.php deleted file mode 100644 index 01b6ef3..0000000 --- a/phpQuery/phpQuery/Zend/Http/Client/Adapter/Socket.php +++ /dev/null @@ -1,332 +0,0 @@ - false, - 'ssltransport' => 'ssl', - 'sslcert' => null, - 'sslpassphrase' => null - ); - - /** - * Request method - will be set by write() and might be used by read() - * - * @var string - */ - protected $method = null; - - /** - * Adapter constructor, currently empty. Config is set using setConfig() - * - */ - public function __construct() - { - } - - /** - * Set the configuration array for the adapter - * - * @param array $config - */ - public function setConfig($config = array()) - { - if (! is_array($config)) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception( - '$config expects an array, ' . gettype($config) . ' recieved.'); - } - - foreach ($config as $k => $v) { - $this->config[strtolower($k)] = $v; - } - } - - /** - * Connect to the remote server - * - * @param string $host - * @param int $port - * @param boolean $secure - * @param int $timeout - */ - public function connect($host, $port = 80, $secure = false) - { - // If the URI should be accessed via SSL, prepend the Hostname with ssl:// - $host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host; - - // If we are connected to the wrong host, disconnect first - if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) { - if (is_resource($this->socket)) $this->close(); - } - - // Now, if we are not connected, connect - if (! is_resource($this->socket) || ! $this->config['keepalive']) { - $context = stream_context_create(); - if ($secure) { - if ($this->config['sslcert'] !== null) { - if (! stream_context_set_option($context, 'ssl', 'local_cert', - $this->config['sslcert'])) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Unable to set sslcert option'); - } - } - if ($this->config['sslpassphrase'] !== null) { - if (! stream_context_set_option($context, 'ssl', 'passphrase', - $this->config['sslpassphrase'])) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Unable to set sslpassphrase option'); - } - } - } - - $flags = STREAM_CLIENT_CONNECT; - if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT; - - $this->socket = @stream_socket_client($host . ':' . $port, - $errno, - $errstr, - (int) $this->config['timeout'], - $flags, - $context); - if (! $this->socket) { - $this->close(); - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception( - 'Unable to Connect to ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr); - } - - // Set the stream timeout - if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Unable to set the connection timeout'); - } - - // Update connected_to - $this->connected_to = array($host, $port); - } - } - - /** - * Send request to the remote server - * - * @param string $method - * @param Zend_Uri_Http $uri - * @param string $http_ver - * @param array $headers - * @param string $body - * @return string Request as string - */ - public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') - { - // Make sure we're properly connected - if (! $this->socket) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are not connected'); - } - - $host = $uri->getHost(); - $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; - if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are connected to the wrong host'); - } - - // Save request method for later - $this->method = $method; - - // Build request headers - $path = $uri->getPath(); - if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); - $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; - foreach ($headers as $k => $v) { - if (is_string($k)) $v = ucfirst($k) . ": $v"; - $request .= "$v\r\n"; - } - - // Add the request body - $request .= "\r\n" . $body; - - // Send the request - if (! @fwrite($this->socket, $request)) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Error writing request to server'); - } - - return $request; - } - - /** - * Read response from server - * - * @return string - */ - public function read() - { - // First, read headers only - $response = ''; - $gotStatus = false; - while ($line = @fgets($this->socket)) { - $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); - if ($gotStatus) { - $response .= $line; - if (!chop($line)) break; - } - } - - $statusCode = Zend_Http_Response::extractCode($response); - - // Handle 100 and 101 responses internally by restarting the read again - if ($statusCode == 100 || $statusCode == 101) return $this->read(); - - /** - * Responses to HEAD requests and 204 or 304 responses are not expected - * to have a body - stop reading here - */ - if ($statusCode == 304 || $statusCode == 204 || - $this->method == Zend_Http_Client::HEAD) return $response; - - // Check headers to see what kind of connection / transfer encoding we have - $headers = Zend_Http_Response::extractHeaders($response); - - // if the connection is set to close, just read until socket closes - if (isset($headers['connection']) && $headers['connection'] == 'close') { - while ($buff = @fread($this->socket, 8192)) { - $response .= $buff; - } - - $this->close(); - - // Else, if we got a transfer-encoding header (chunked body) - } elseif (isset($headers['transfer-encoding'])) { - if ($headers['transfer-encoding'] == 'chunked') { - do { - $chunk = ''; - $line = @fgets($this->socket); - $chunk .= $line; - - $hexchunksize = ltrim(chop($line), '0'); - $hexchunksize = strlen($hexchunksize) ? strtolower($hexchunksize) : 0; - - $chunksize = hexdec(chop($line)); - if (dechex($chunksize) != $hexchunksize) { - @fclose($this->socket); - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception('Invalid chunk size "' . - $hexchunksize . '" unable to read chunked body'); - } - - $left_to_read = $chunksize; - while ($left_to_read > 0) { - $line = @fread($this->socket, $left_to_read); - $chunk .= $line; - $left_to_read -= strlen($line); - } - - $chunk .= @fgets($this->socket); - $response .= $chunk; - } while ($chunksize > 0); - } else { - throw new Zend_Http_Client_Adapter_Exception('Cannot handle "' . - $headers['transfer-encoding'] . '" transfer encoding'); - } - - // Else, if we got the content-length header, read this number of bytes - } elseif (isset($headers['content-length'])) { - $left_to_read = $headers['content-length']; - $chunk = ''; - while ($left_to_read > 0) { - $chunk = @fread($this->socket, $left_to_read); - $left_to_read -= strlen($chunk); - $response .= $chunk; - } - - // Fallback: just read the response (should not happen) - } else { - while ($buff = @fread($this->socket, 8192)) { - $response .= $buff; - } - - $this->close(); - } - - return $response; - } - - /** - * Close the connection to the server - * - */ - public function close() - { - if (is_resource($this->socket)) @fclose($this->socket); - $this->socket = null; - $this->connected_to = array(null, null); - } - - /** - * Destructor: make sure the socket is disconnected - * - * If we are in persistent TCP mode, will not close the connection - * - */ - public function __destruct() - { - if (! $this->config['persistent']) { - if ($this->socket) $this->close(); - } - } -} diff --git a/phpQuery/phpQuery/Zend/Http/Client/Adapter/Test.php b/phpQuery/phpQuery/Zend/Http/Client/Adapter/Test.php deleted file mode 100644 index ce5c468..0000000 --- a/phpQuery/phpQuery/Zend/Http/Client/Adapter/Test.php +++ /dev/null @@ -1,193 +0,0 @@ - $v) { - $this->config[strtolower($k)] = $v; - } - } - - /** - * Connect to the remote server - * - * @param string $host - * @param int $port - * @param boolean $secure - * @param int $timeout - */ - public function connect($host, $port = 80, $secure = false) - { } - - /** - * Send request to the remote server - * - * @param string $method - * @param Zend_Uri_Http $uri - * @param string $http_ver - * @param array $headers - * @param string $body - * @return string Request as string - */ - public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') - { - $host = $uri->getHost(); - $host = (strtolower($uri->getScheme()) == 'https' ? 'sslv2://' . $host : $host); - - // Build request headers - $path = $uri->getPath(); - if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); - $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; - foreach ($headers as $k => $v) { - if (is_string($k)) $v = ucfirst($k) . ": $v"; - $request .= "$v\r\n"; - } - - // Add the request body - $request .= "\r\n" . $body; - - // Do nothing - just return the request as string - - return $request; - } - - /** - * Return the response set in $this->setResponse() - * - * @return string - */ - public function read() - { - if ($this->responseIndex >= count($this->responses)) { - $this->responseIndex = 0; - } - return $this->responses[$this->responseIndex++]; - } - - /** - * Close the connection (dummy) - * - */ - public function close() - { } - - /** - * Set the HTTP response(s) to be returned by this adapter - * - * @param Zend_Http_Response|array|string $response - */ - public function setResponse($response) - { - if ($response instanceof Zend_Http_Response) { - $response = $response->asString(); - } - - $this->responses = (array)$response; - $this->responseIndex = 0; - } - - /** - * Add another response to the response buffer. - * - * @param string $response - */ - public function addResponse($response) - { - $this->responses[] = $response; - } - - /** - * Sets the position of the response buffer. Selects which - * response will be returned on the next call to read(). - * - * @param integer $index - */ - public function setResponseIndex($index) - { - if ($index < 0 || $index >= count($this->responses)) { - require_once 'Zend/Http/Client/Adapter/Exception.php'; - throw new Zend_Http_Client_Adapter_Exception( - 'Index out of range of response buffer size'); - } - $this->responseIndex = $index; - } -} diff --git a/phpQuery/phpQuery/Zend/Http/Client/Exception.php b/phpQuery/phpQuery/Zend/Http/Client/Exception.php deleted file mode 100644 index 70c8e01..0000000 --- a/phpQuery/phpQuery/Zend/Http/Client/Exception.php +++ /dev/null @@ -1,33 +0,0 @@ -name = (string) $name) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('Cookies must have a name'); - } - - if (! $this->domain = (string) $domain) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('Cookies must have a domain'); - } - - $this->value = (string) $value; - $this->expires = ($expires === null ? null : (int) $expires); - $this->path = ($path ? $path : '/'); - $this->secure = $secure; - } - - /** - * Get Cookie name - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Get cookie value - * - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * Get cookie domain - * - * @return string - */ - public function getDomain() - { - return $this->domain; - } - - /** - * Get the cookie path - * - * @return string - */ - public function getPath() - { - return $this->path; - } - - /** - * Get the expiry time of the cookie, or null if no expiry time is set - * - * @return int|null - */ - public function getExpiryTime() - { - return $this->expires; - } - - /** - * Check whether the cookie should only be sent over secure connections - * - * @return boolean - */ - public function isSecure() - { - return $this->secure; - } - - /** - * Check whether the cookie has expired - * - * Always returns false if the cookie is a session cookie (has no expiry time) - * - * @param int $now Timestamp to consider as "now" - * @return boolean - */ - public function isExpired($now = null) - { - if ($now === null) $now = time(); - if (is_int($this->expires) && $this->expires < $now) { - return true; - } else { - return false; - } - } - - /** - * Check whether the cookie is a session cookie (has no expiry time set) - * - * @return boolean - */ - public function isSessionCookie() - { - return ($this->expires === null); - } - - /** - * Checks whether the cookie should be sent or not in a specific scenario - * - * @param string|Zend_Uri_Http $uri URI to check against (secure, domain, path) - * @param boolean $matchSessionCookies Whether to send session cookies - * @param int $now Override the current time when checking for expiry time - * @return boolean - */ - public function match($uri, $matchSessionCookies = true, $now = null) - { - if (is_string ($uri)) { - $uri = Zend_Uri_Http::factory($uri); - } - - // Make sure we have a valid Zend_Uri_Http object - if (! ($uri->valid() && ($uri->getScheme() == 'http' || $uri->getScheme() =='https'))) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('Passed URI is not a valid HTTP or HTTPS URI'); - } - - // Check that the cookie is secure (if required) and not expired - if ($this->secure && $uri->getScheme() != 'https') return false; - if ($this->isExpired($now)) return false; - if ($this->isSessionCookie() && ! $matchSessionCookies) return false; - - // Validate domain and path - // Domain is validated using tail match, while path is validated using head match - $domain_preg = preg_quote($this->getDomain(), "/"); - if (! preg_match("/{$domain_preg}$/", $uri->getHost())) return false; - $path_preg = preg_quote($this->getPath(), "/"); - if (! preg_match("/^{$path_preg}/", $uri->getPath())) return false; - - // If we didn't die until now, return true. - return true; - } - - /** - * Get the cookie as a string, suitable for sending as a "Cookie" header in an - * HTTP request - * - * @return string - */ - public function __toString() - { - return $this->name . '=' . urlencode($this->value) . ';'; - } - - /** - * Generate a new Cookie object from a cookie string - * (for example the value of the Set-Cookie HTTP header) - * - * @param string $cookieStr - * @param Zend_Uri_Http|string $ref_uri Reference URI for default values (domain, path) - * @return Zend_Http_Cookie A new Zend_Http_Cookie object or false on failure. - */ - public static function fromString($cookieStr, $ref_uri = null) - { - // Set default values - if (is_string($ref_uri)) { - $ref_uri = Zend_Uri_Http::factory($ref_uri); - } - - $name = ''; - $value = ''; - $domain = ''; - $path = ''; - $expires = null; - $secure = false; - $parts = explode(';', $cookieStr); - - // If first part does not include '=', fail - if (strpos($parts[0], '=') === false) return false; - - // Get the name and value of the cookie - list($name, $value) = explode('=', trim(array_shift($parts)), 2); - $name = trim($name); - $value = urldecode(trim($value)); - - // Set default domain and path - if ($ref_uri instanceof Zend_Uri_Http) { - $domain = $ref_uri->getHost(); - $path = $ref_uri->getPath(); - $path = substr($path, 0, strrpos($path, '/')); - } - - // Set other cookie parameters - foreach ($parts as $part) { - $part = trim($part); - if (strtolower($part) == 'secure') { - $secure = true; - continue; - } - - $keyValue = explode('=', $part, 2); - if (count($keyValue) == 2) { - list($k, $v) = $keyValue; - switch (strtolower($k)) { - case 'expires': - $expires = strtotime($v); - break; - case 'path': - $path = $v; - break; - case 'domain': - $domain = $v; - break; - default: - break; - } - } - } - - if ($name !== '') { - return new Zend_Http_Cookie($name, $value, $domain, $expires, $path, $secure); - } else { - return false; - } - } -} diff --git a/phpQuery/phpQuery/Zend/Http/CookieJar.php b/phpQuery/phpQuery/Zend/Http/CookieJar.php deleted file mode 100644 index c11174e..0000000 --- a/phpQuery/phpQuery/Zend/Http/CookieJar.php +++ /dev/null @@ -1,350 +0,0 @@ -getDomain(); - $path = $cookie->getPath(); - if (! isset($this->cookies[$domain])) $this->cookies[$domain] = array(); - if (! isset($this->cookies[$domain][$path])) $this->cookies[$domain][$path] = array(); - $this->cookies[$domain][$path][$cookie->getName()] = $cookie; - } else { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('Supplient argument is not a valid cookie string or object'); - } - } - - /** - * Parse an HTTP response, adding all the cookies set in that response - * to the cookie jar. - * - * @param Zend_Http_Response $response - * @param Zend_Uri_Http|string $ref_uri Requested URI - */ - public function addCookiesFromResponse($response, $ref_uri) - { - if (! $response instanceof Zend_Http_Response) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('$response is expected to be a Response object, ' . - gettype($response) . ' was passed'); - } - - $cookie_hdrs = $response->getHeader('Set-Cookie'); - - if (is_array($cookie_hdrs)) { - foreach ($cookie_hdrs as $cookie) { - $this->addCookie($cookie, $ref_uri); - } - } elseif (is_string($cookie_hdrs)) { - $this->addCookie($cookie_hdrs, $ref_uri); - } - } - - /** - * Get all cookies in the cookie jar as an array - * - * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings - * @return array|string - */ - public function getAllCookies($ret_as = self::COOKIE_OBJECT) - { - $cookies = $this->_flattenCookiesArray($this->cookies, $ret_as); - return $cookies; - } - - /** - * Return an array of all cookies matching a specific request according to the request URI, - * whether session cookies should be sent or not, and the time to consider as "now" when - * checking cookie expiry time. - * - * @param string|Zend_Uri_Http $uri URI to check against (secure, domain, path) - * @param boolean $matchSessionCookies Whether to send session cookies - * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings - * @param int $now Override the current time when checking for expiry time - * @return array|string - */ - public function getMatchingCookies($uri, $matchSessionCookies = true, - $ret_as = self::COOKIE_OBJECT, $now = null) - { - if (is_string($uri)) $uri = Zend_Uri::factory($uri); - if (! $uri instanceof Zend_Uri_Http) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception("Invalid URI string or object passed"); - } - - // Set path - $path = $uri->getPath(); - $path = substr($path, 0, strrpos($path, '/')); - if (! $path) $path = '/'; - - // First, reduce the array of cookies to only those matching domain and path - $cookies = $this->_matchDomain($uri->getHost()); - $cookies = $this->_matchPath($cookies, $path); - $cookies = $this->_flattenCookiesArray($cookies, self::COOKIE_OBJECT); - - // Next, run Cookie->match on all cookies to check secure, time and session mathcing - $ret = array(); - foreach ($cookies as $cookie) - if ($cookie->match($uri, $matchSessionCookies, $now)) - $ret[] = $cookie; - - // Now, use self::_flattenCookiesArray again - only to convert to the return format ;) - $ret = $this->_flattenCookiesArray($ret, $ret_as); - - return $ret; - } - - /** - * Get a specific cookie according to a URI and name - * - * @param Zend_Uri_Http|string $uri The uri (domain and path) to match - * @param string $cookie_name The cookie's name - * @param int $ret_as Whether to return cookies as objects of Zend_Http_Cookie or as strings - * @return Zend_Http_Cookie|string - */ - public function getCookie($uri, $cookie_name, $ret_as = self::COOKIE_OBJECT) - { - if (is_string($uri)) { - $uri = Zend_Uri::factory($uri); - } - - if (! $uri instanceof Zend_Uri_Http) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('Invalid URI specified'); - } - - // Get correct cookie path - $path = $uri->getPath(); - $path = substr($path, 0, strrpos($path, '/')); - if (! $path) $path = '/'; - - if (isset($this->cookies[$uri->getHost()][$path][$cookie_name])) { - $cookie = $this->cookies[$uri->getHost()][$path][$cookie_name]; - - switch ($ret_as) { - case self::COOKIE_OBJECT: - return $cookie; - break; - - case self::COOKIE_STRING_ARRAY: - case self::COOKIE_STRING_CONCAT: - return $cookie->__toString(); - break; - - default: - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception("Invalid value passed for \$ret_as: {$ret_as}"); - break; - } - } else { - return false; - } - } - - /** - * Helper function to recursivly flatten an array. Shoud be used when exporting the - * cookies array (or parts of it) - * - * @param Zend_Http_Cookie|array $ptr - * @param int $ret_as What value to return - * @return array|string - */ - protected function _flattenCookiesArray($ptr, $ret_as = self::COOKIE_OBJECT) { - if (is_array($ptr)) { - $ret = ($ret_as == self::COOKIE_STRING_CONCAT ? '' : array()); - foreach ($ptr as $item) { - if ($ret_as == self::COOKIE_STRING_CONCAT) { - $ret .= $this->_flattenCookiesArray($item, $ret_as); - } else { - $ret = array_merge($ret, $this->_flattenCookiesArray($item, $ret_as)); - } - } - return $ret; - } elseif ($ptr instanceof Zend_Http_Cookie) { - switch ($ret_as) { - case self::COOKIE_STRING_ARRAY: - return array($ptr->__toString()); - break; - - case self::COOKIE_STRING_CONCAT: - return $ptr->__toString(); - break; - - case self::COOKIE_OBJECT: - default: - return array($ptr); - break; - } - } - - return null; - } - - /** - * Return a subset of the cookies array matching a specific domain - * - * Returned array is actually an array of pointers to items in the $this->cookies array. - * - * @param string $domain - * @return array - */ - protected function _matchDomain($domain) { - $ret = array(); - - foreach (array_keys($this->cookies) as $cdom) { - $regex = "/" . preg_quote($cdom, "/") . "$/i"; - if (preg_match($regex, $domain)) $ret[$cdom] = &$this->cookies[$cdom]; - } - - return $ret; - } - - /** - * Return a subset of a domain-matching cookies that also match a specified path - * - * Returned array is actually an array of pointers to items in the $passed array. - * - * @param array $dom_array - * @param string $path - * @return array - */ - protected function _matchPath($domains, $path) { - $ret = array(); - if (substr($path, -1) != '/') $path .= '/'; - - foreach ($domains as $dom => $paths_array) { - foreach (array_keys($paths_array) as $cpath) { - $regex = "|^" . preg_quote($cpath, "|") . "|i"; - if (preg_match($regex, $path)) { - if (! isset($ret[$dom])) $ret[$dom] = array(); - $ret[$dom][$cpath] = &$paths_array[$cpath]; - } - } - } - - return $ret; - } - - /** - * Create a new CookieJar object and automatically load into it all the - * cookies set in an Http_Response object. If $uri is set, it will be - * considered as the requested URI for setting default domain and path - * of the cookie. - * - * @param Zend_Http_Response $response HTTP Response object - * @param Zend_Uri_Http|string $uri The requested URI - * @return Zend_Http_CookieJar - * @todo Add the $uri functionality. - */ - public static function fromResponse(Zend_Http_Response $response, $ref_uri) - { - $jar = new self(); - $jar->addCookiesFromResponse($response, $ref_uri); - return $jar; - } -} diff --git a/phpQuery/phpQuery/Zend/Http/Exception.php b/phpQuery/phpQuery/Zend/Http/Exception.php deleted file mode 100644 index 76e2a8d..0000000 --- a/phpQuery/phpQuery/Zend/Http/Exception.php +++ /dev/null @@ -1,33 +0,0 @@ - 'Continue', - 101 => 'Switching Protocols', - - // Success 2xx - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - - // Redirection 3xx - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', // 1.1 - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - // 306 is deprecated but reserved - 307 => 'Temporary Redirect', - - // Client Error 4xx - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - - // Server Error 5xx - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - 509 => 'Bandwidth Limit Exceeded' - ); - - /** - * The HTTP version (1.0, 1.1) - * - * @var string - */ - protected $version; - - /** - * The HTTP response code - * - * @var int - */ - protected $code; - - /** - * The HTTP response code as string - * (e.g. 'Not Found' for 404 or 'Internal Server Error' for 500) - * - * @var string - */ - protected $message; - - /** - * The HTTP response headers array - * - * @var array - */ - protected $headers = array(); - - /** - * The HTTP response body - * - * @var string - */ - protected $body; - - /** - * HTTP response constructor - * - * In most cases, you would use Zend_Http_Response::fromString to parse an HTTP - * response string and create a new Zend_Http_Response object. - * - * NOTE: The constructor no longer accepts nulls or empty values for the code and - * headers and will throw an exception if the passed values do not form a valid HTTP - * responses. - * - * If no message is passed, the message will be guessed according to the response code. - * - * @param int $code Response code (200, 404, ...) - * @param array $headers Headers array - * @param string $body Response body - * @param string $version HTTP version - * @param string $message Response code as text - * @throws Zend_Http_Exception - */ - public function __construct($code, $headers, $body = null, $version = '1.1', $message = null) - { - // Make sure the response code is valid and set it - if (self::responseCodeAsText($code) === null) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception("{$code} is not a valid HTTP response code"); - } - - $this->code = $code; - - // Make sure we got valid headers and set them - if (! is_array($headers)) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('No valid headers were passed'); - } - - foreach ($headers as $name => $value) { - if (is_int($name)) - list($name, $value) = explode(": ", $value, 1); - - $this->headers[ucwords(strtolower($name))] = $value; - } - - // Set the body - $this->body = $body; - - // Set the HTTP version - if (! preg_match('|^\d\.\d$|', $version)) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception("Invalid HTTP response version: $version"); - } - - $this->version = $version; - - // If we got the response message, set it. Else, set it according to - // the response code - if (is_string($message)) { - $this->message = $message; - } else { - $this->message = self::responseCodeAsText($code); - } - } - - /** - * Check whether the response is an error - * - * @return boolean - */ - public function isError() - { - $restype = floor($this->code / 100); - if ($restype == 4 || $restype == 5) { - return true; - } - - return false; - } - - /** - * Check whether the response in successful - * - * @return boolean - */ - public function isSuccessful() - { - $restype = floor($this->code / 100); - if ($restype == 2 || $restype == 1) { // Shouldn't 3xx count as success as well ??? - return true; - } - - return false; - } - - /** - * Check whether the response is a redirection - * - * @return boolean - */ - public function isRedirect() - { - $restype = floor($this->code / 100); - if ($restype == 3) { - return true; - } - - return false; - } - - /** - * Get the response body as string - * - * This method returns the body of the HTTP response (the content), as it - * should be in it's readable version - that is, after decoding it (if it - * was decoded), deflating it (if it was gzip compressed), etc. - * - * If you want to get the raw body (as transfered on wire) use - * $this->getRawBody() instead. - * - * @return string - */ - public function getBody() - { - $body = ''; - - // Decode the body if it was transfer-encoded - switch ($this->getHeader('transfer-encoding')) { - - // Handle chunked body - case 'chunked': - $body = self::decodeChunkedBody($this->body); - break; - - // No transfer encoding, or unknown encoding extension: - // return body as is - default: - $body = $this->body; - break; - } - - // Decode any content-encoding (gzip or deflate) if needed - switch (strtolower($this->getHeader('content-encoding'))) { - - // Handle gzip encoding - case 'gzip': - $body = self::decodeGzip($body); - break; - - // Handle deflate encoding - case 'deflate': - $body = self::decodeDeflate($body); - break; - - default: - break; - } - - return $body; - } - - /** - * Get the raw response body (as transfered "on wire") as string - * - * If the body is encoded (with Transfer-Encoding, not content-encoding - - * IE "chunked" body), gzip compressed, etc. it will not be decoded. - * - * @return string - */ - public function getRawBody() - { - return $this->body; - } - - /** - * Get the HTTP version of the response - * - * @return string - */ - public function getVersion() - { - return $this->version; - } - - /** - * Get the HTTP response status code - * - * @return int - */ - public function getStatus() - { - return $this->code; - } - - /** - * Return a message describing the HTTP response code - * (Eg. "OK", "Not Found", "Moved Permanently") - * - * @return string - */ - public function getMessage() - { - return $this->message; - } - - /** - * Get the response headers - * - * @return array - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * Get a specific header as string, or null if it is not set - * - * @param string$header - * @return string|array|null - */ - public function getHeader($header) - { - $header = ucwords(strtolower($header)); - if (! is_string($header) || ! isset($this->headers[$header])) return null; - - return $this->headers[$header]; - } - - /** - * Get all headers as string - * - * @param boolean $status_line Whether to return the first status line (IE "HTTP 200 OK") - * @param string $br Line breaks (eg. "\n", "\r\n", "
") - * @return string - */ - public function getHeadersAsString($status_line = true, $br = "\n") - { - $str = ''; - - if ($status_line) { - $str = "HTTP/{$this->version} {$this->code} {$this->message}{$br}"; - } - - // Iterate over the headers and stringify them - foreach ($this->headers as $name => $value) - { - if (is_string($value)) - $str .= "{$name}: {$value}{$br}"; - - elseif (is_array($value)) { - foreach ($value as $subval) { - $str .= "{$name}: {$subval}{$br}"; - } - } - } - - return $str; - } - - /** - * Get the entire response as string - * - * @param string $br Line breaks (eg. "\n", "\r\n", "
") - * @return string - */ - public function asString($br = "\n") - { - return $this->getHeadersAsString(true, $br) . $br . $this->getRawBody(); - } - - /** - * A convenience function that returns a text representation of - * HTTP response codes. Returns 'Unknown' for unknown codes. - * Returns array of all codes, if $code is not specified. - * - * Conforms to HTTP/1.1 as defined in RFC 2616 (except for 'Unknown') - * See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10 for reference - * - * @param int $code HTTP response code - * @param boolean $http11 Use HTTP version 1.1 - * @return string - */ - public static function responseCodeAsText($code = null, $http11 = true) - { - $messages = self::$messages; - if (! $http11) $messages[302] = 'Moved Temporarily'; - - if ($code === null) { - return $messages; - } elseif (isset($messages[$code])) { - return $messages[$code]; - } else { - return 'Unknown'; - } - } - - /** - * Extract the response code from a response string - * - * @param string $response_str - * @return int - */ - public static function extractCode($response_str) - { - preg_match("|^HTTP/[\d\.x]+ (\d+)|", $response_str, $m); - - if (isset($m[1])) { - return (int) $m[1]; - } else { - return false; - } - } - - /** - * Extract the HTTP message from a response - * - * @param string $response_str - * @return string - */ - public static function extractMessage($response_str) - { - preg_match("|^HTTP/[\d\.x]+ \d+ ([^\r\n]+)|", $response_str, $m); - - if (isset($m[1])) { - return $m[1]; - } else { - return false; - } - } - - /** - * Extract the HTTP version from a response - * - * @param string $response_str - * @return string - */ - public static function extractVersion($response_str) - { - preg_match("|^HTTP/([\d\.x]+) \d+|", $response_str, $m); - - if (isset($m[1])) { - return $m[1]; - } else { - return false; - } - } - - /** - * Extract the headers from a response string - * - * @param string $response_str - * @return array - */ - public static function extractHeaders($response_str) - { - $headers = array(); - - // First, split body and headers - $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); - if (! $parts[0]) return $headers; - - // Split headers part to lines - $lines = explode("\n", $parts[0]); - unset($parts); - $last_header = null; - - foreach($lines as $line) { - $line = trim($line, "\r\n"); - if ($line == "") break; - - if (preg_match("|^([\w-]+):\s+(.+)|", $line, $m)) { - unset($last_header); - $h_name = strtolower($m[1]); - $h_value = $m[2]; - - if (isset($headers[$h_name])) { - if (! is_array($headers[$h_name])) { - $headers[$h_name] = array($headers[$h_name]); - } - - $headers[$h_name][] = $h_value; - } else { - $headers[$h_name] = $h_value; - } - $last_header = $h_name; - } elseif (preg_match("|^\s+(.+)$|", $line, $m) && $last_header !== null) { - if (is_array($headers[$last_header])) { - end($headers[$last_header]); - $last_header_key = key($headers[$last_header]); - $headers[$last_header][$last_header_key] .= $m[1]; - } else { - $headers[$last_header] .= $m[1]; - } - } - } - - return $headers; - } - - /** - * Extract the body from a response string - * - * @param string $response_str - * @return string - */ - public static function extractBody($response_str) - { - $parts = preg_split('|(?:\r?\n){2}|m', $response_str, 2); - if (isset($parts[1])) { - return $parts[1]; - } else { - return ''; - } - } - - /** - * Decode a "chunked" transfer-encoded body and return the decoded text - * - * @param string $body - * @return string - */ - public static function decodeChunkedBody($body) - { - $decBody = ''; - - while (trim($body)) { - if (! preg_match("/^([\da-fA-F]+)[^\r\n]*\r\n/sm", $body, $m)) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception("Error parsing body - doesn't seem to be a chunked message"); - } - - $length = hexdec(trim($m[1])); - $cut = strlen($m[0]); - - $decBody .= substr($body, $cut, $length); - $body = substr($body, $cut + $length + 2); - } - - return $decBody; - } - - /** - * Decode a gzip encoded message (when Content-encoding = gzip) - * - * Currently requires PHP with zlib support - * - * @param string $body - * @return string - */ - public static function decodeGzip($body) - { - if (! function_exists('gzinflate')) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('Unable to decode gzipped response ' . - 'body: perhaps the zlib extension is not loaded?'); - } - - return gzinflate(substr($body, 10)); - } - - /** - * Decode a zlib deflated message (when Content-encoding = deflate) - * - * Currently requires PHP with zlib support - * - * @param string $body - * @return string - */ - public static function decodeDeflate($body) - { - if (! function_exists('gzuncompress')) { - require_once 'Zend/Http/Exception.php'; - throw new Zend_Http_Exception('Unable to decode deflated response ' . - 'body: perhaps the zlib extension is not loaded?'); - } - - return gzuncompress($body); - } - - /** - * Create a new Zend_Http_Response object from a string - * - * @param string $response_str - * @return Zend_Http_Response - */ - public static function fromString($response_str) - { - $code = self::extractCode($response_str); - $headers = self::extractHeaders($response_str); - $body = self::extractBody($response_str); - $version = self::extractVersion($response_str); - $message = self::extractMessage($response_str); - - return new Zend_Http_Response($code, $headers, $body, $version, $message); - } -} diff --git a/phpQuery/phpQuery/Zend/Json/Decoder.php b/phpQuery/phpQuery/Zend/Json/Decoder.php deleted file mode 100644 index c5f1f25..0000000 --- a/phpQuery/phpQuery/Zend/Json/Decoder.php +++ /dev/null @@ -1,457 +0,0 @@ -_source = $source; - $this->_sourceLength = strlen($source); - $this->_token = self::EOF; - $this->_offset = 0; - - // Normalize and set $decodeType - if (!in_array($decodeType, array(Zend_Json::TYPE_ARRAY, Zend_Json::TYPE_OBJECT))) - { - $decodeType = Zend_Json::TYPE_ARRAY; - } - $this->_decodeType = $decodeType; - - // Set pointer at first token - $this->_getNextToken(); - } - - /** - * Decode a JSON source string - * - * Decodes a JSON encoded string. The value returned will be one of the - * following: - * - integer - * - float - * - boolean - * - null - * - StdClass - * - array - * - array of one or more of the above types - * - * By default, decoded objects will be returned as associative arrays; to - * return a StdClass object instead, pass {@link Zend_Json::TYPE_OBJECT} to - * the $objectDecodeType parameter. - * - * Throws a Zend_Json_Exception if the source string is null. - * - * @static - * @access public - * @param string $source String to be decoded - * @param int $objectDecodeType How objects should be decoded; should be - * either or {@link Zend_Json::TYPE_ARRAY} or - * {@link Zend_Json::TYPE_OBJECT}; defaults to TYPE_ARRAY - * @return mixed - * @throws Zend_Json_Exception - */ - public static function decode($source = null, $objectDecodeType = Zend_Json::TYPE_ARRAY) - { - if (null === $source) { - throw new Zend_Json_Exception('Must specify JSON encoded source for decoding'); - } elseif (!is_string($source)) { - throw new Zend_Json_Exception('Can only decode JSON encoded strings'); - } - - $decoder = new self($source, $objectDecodeType); - - return $decoder->_decodeValue(); - } - - - /** - * Recursive driving rountine for supported toplevel tops - * - * @return mixed - */ - protected function _decodeValue() - { - switch ($this->_token) { - case self::DATUM: - $result = $this->_tokenValue; - $this->_getNextToken(); - return($result); - break; - case self::LBRACE: - return($this->_decodeObject()); - break; - case self::LBRACKET: - return($this->_decodeArray()); - break; - default: - return null; - break; - } - } - - /** - * Decodes an object of the form: - * { "attribute: value, "attribute2" : value,...} - * - * If Zend_Json_Encoder was used to encode the original object then - * a special attribute called __className which specifies a class - * name that should wrap the data contained within the encoded source. - * - * Decodes to either an array or StdClass object, based on the value of - * {@link $_decodeType}. If invalid $_decodeType present, returns as an - * array. - * - * @return array|StdClass - */ - protected function _decodeObject() - { - $members = array(); - $tok = $this->_getNextToken(); - - while ($tok && $tok != self::RBRACE) { - if ($tok != self::DATUM || ! is_string($this->_tokenValue)) { - throw new Zend_Json_Exception('Missing key in object encoding: ' . $this->_source); - } - - $key = $this->_tokenValue; - $tok = $this->_getNextToken(); - - if ($tok != self::COLON) { - throw new Zend_Json_Exception('Missing ":" in object encoding: ' . $this->_source); - } - - $tok = $this->_getNextToken(); - $members[$key] = $this->_decodeValue(); - $tok = $this->_token; - - if ($tok == self::RBRACE) { - break; - } - - if ($tok != self::COMMA) { - throw new Zend_Json_Exception('Missing "," in object encoding: ' . $this->_source); - } - - $tok = $this->_getNextToken(); - } - - switch ($this->_decodeType) { - case Zend_Json::TYPE_OBJECT: - // Create new StdClass and populate with $members - $result = new StdClass(); - foreach ($members as $key => $value) { - $result->$key = $value; - } - break; - case Zend_Json::TYPE_ARRAY: - default: - $result = $members; - break; - } - - $this->_getNextToken(); - return $result; - } - - /** - * Decodes a JSON array format: - * [element, element2,...,elementN] - * - * @return array - */ - protected function _decodeArray() - { - $result = array(); - $starttok = $tok = $this->_getNextToken(); // Move past the '[' - $index = 0; - - while ($tok && $tok != self::RBRACKET) { - $result[$index++] = $this->_decodeValue(); - - $tok = $this->_token; - - if ($tok == self::RBRACKET || !$tok) { - break; - } - - if ($tok != self::COMMA) { - throw new Zend_Json_Exception('Missing "," in array encoding: ' . $this->_source); - } - - $tok = $this->_getNextToken(); - } - - $this->_getNextToken(); - return($result); - } - - - /** - * Removes whitepsace characters from the source input - */ - protected function _eatWhitespace() - { - if (preg_match( - '/([\t\b\f\n\r ])*/s', - $this->_source, - $matches, - PREG_OFFSET_CAPTURE, - $this->_offset) - && $matches[0][1] == $this->_offset) - { - $this->_offset += strlen($matches[0][0]); - } - } - - - /** - * Retrieves the next token from the source stream - * - * @return int Token constant value specified in class definition - */ - protected function _getNextToken() - { - $this->_token = self::EOF; - $this->_tokenValue = null; - $this->_eatWhitespace(); - - if ($this->_offset >= $this->_sourceLength) { - return(self::EOF); - } - - $str = $this->_source; - $str_length = $this->_sourceLength; - $i = $this->_offset; - $start = $i; - - switch ($str{$i}) { - case '{': - $this->_token = self::LBRACE; - break; - case '}': - $this->_token = self::RBRACE; - break; - case '[': - $this->_token = self::LBRACKET; - break; - case ']': - $this->_token = self::RBRACKET; - break; - case ',': - $this->_token = self::COMMA; - break; - case ':': - $this->_token = self::COLON; - break; - case '"': - $result = ''; - do { - $i++; - if ($i >= $str_length) { - break; - } - - $chr = $str{$i}; - if ($chr == '\\') { - $i++; - if ($i >= $str_length) { - break; - } - $chr = $str{$i}; - switch ($chr) { - case '"' : - $result .= '"'; - break; - case '\\': - $result .= '\\'; - break; - case '/' : - $result .= '/'; - break; - case 'b' : - $result .= chr(8); - break; - case 'f' : - $result .= chr(12); - break; - case 'n' : - $result .= chr(10); - break; - case 'r' : - $result .= chr(13); - break; - case 't' : - $result .= chr(9); - break; - case '\'' : - $result .= '\''; - break; - default: - throw new Zend_Json_Exception("Illegal escape " - . "sequence '" . $chr . "'"); - } - } elseif ($chr == '"') { - break; - } else { - $result .= $chr; - } - } while ($i < $str_length); - - $this->_token = self::DATUM; - //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1); - $this->_tokenValue = $result; - break; - case 't': - if (($i+ 3) < $str_length && substr($str, $start, 4) == "true") { - $this->_token = self::DATUM; - } - $this->_tokenValue = true; - $i += 3; - break; - case 'f': - if (($i+ 4) < $str_length && substr($str, $start, 5) == "false") { - $this->_token = self::DATUM; - } - $this->_tokenValue = false; - $i += 4; - break; - case 'n': - if (($i+ 3) < $str_length && substr($str, $start, 4) == "null") { - $this->_token = self::DATUM; - } - $this->_tokenValue = NULL; - $i += 3; - break; - } - - if ($this->_token != self::EOF) { - $this->_offset = $i + 1; // Consume the last token character - return($this->_token); - } - - $chr = $str{$i}; - if ($chr == '-' || $chr == '.' || ($chr >= '0' && $chr <= '9')) { - if (preg_match('/-?([0-9])*(\.[0-9]*)?((e|E)((-|\+)?)[0-9]+)?/s', - $str, $matches, PREG_OFFSET_CAPTURE, $start) && $matches[0][1] == $start) { - - $datum = $matches[0][0]; - - if (is_numeric($datum)) { - if (preg_match('/^0\d+$/', $datum)) { - throw new Zend_Json_Exception("Octal notation not supported by JSON (value: $datum)"); - } else { - $val = intval($datum); - $fVal = floatval($datum); - $this->_tokenValue = ($val == $fVal ? $val : $fVal); - } - } else { - throw new Zend_Json_Exception("Illegal number format: $datum"); - } - - $this->_token = self::DATUM; - $this->_offset = $start + strlen($datum); - } - } else { - throw new Zend_Json_Exception('Illegal Token'); - } - - return($this->_token); - } -} - diff --git a/phpQuery/phpQuery/Zend/Json/Encoder.php b/phpQuery/phpQuery/Zend/Json/Encoder.php deleted file mode 100644 index ce2024a..0000000 --- a/phpQuery/phpQuery/Zend/Json/Encoder.php +++ /dev/null @@ -1,431 +0,0 @@ -_cycleCheck = $cycleCheck; - $this->_options = $options; - } - - /** - * Use the JSON encoding scheme for the value specified - * - * @param mixed $value The value to be encoded - * @param boolean $cycleCheck Whether or not to check for possible object recursion when encoding - * @param array $options Additional options used during encoding - * @return string The encoded value - */ - public static function encode($value, $cycleCheck = false, $options = array()) - { - $encoder = new self(($cycleCheck) ? true : false, $options); - - return $encoder->_encodeValue($value); - } - - /** - * Recursive driver which determines the type of value to be encoded - * and then dispatches to the appropriate method. $values are either - * - objects (returns from {@link _encodeObject()}) - * - arrays (returns from {@link _encodeArray()}) - * - basic datums (e.g. numbers or strings) (returns from {@link _encodeDatum()}) - * - * @param $value mixed The value to be encoded - * @return string Encoded value - */ - protected function _encodeValue(&$value) - { - if (is_object($value)) { - return $this->_encodeObject($value); - } else if (is_array($value)) { - return $this->_encodeArray($value); - } - - return $this->_encodeDatum($value); - } - - - - /** - * Encode an object to JSON by encoding each of the public properties - * - * A special property is added to the JSON object called '__className' - * that contains the name of the class of $value. This is used to decode - * the object on the client into a specific class. - * - * @param $value object - * @return string - * @throws Zend_Json_Exception If recursive checks are enabled and the object has been serialized previously - */ - protected function _encodeObject(&$value) - { - if ($this->_cycleCheck) { - if ($this->_wasVisited($value)) { - - if (isset($this->_options['silenceCyclicalExceptions']) - && $this->_options['silenceCyclicalExceptions']===true) { - - return '"* RECURSION (' . get_class($value) . ') *"'; - - } else { - throw new Zend_Json_Exception( - 'Cycles not supported in JSON encoding, cycle introduced by ' - . 'class "' . get_class($value) . '"' - ); - } - } - - $this->_visited[] = $value; - } - - $props = ''; - foreach (get_object_vars($value) as $name => $propValue) { - if (isset($propValue)) { - $props .= ',' - . $this->_encodeValue($name) - . ':' - . $this->_encodeValue($propValue); - } - } - - return '{"__className":"' . get_class($value) . '"' - . $props . '}'; - } - - - /** - * Determine if an object has been serialized already - * - * @param mixed $value - * @return boolean - */ - protected function _wasVisited(&$value) - { - if (in_array($value, $this->_visited, true)) { - return true; - } - - return false; - } - - - /** - * JSON encode an array value - * - * Recursively encodes each value of an array and returns a JSON encoded - * array string. - * - * Arrays are defined as integer-indexed arrays starting at index 0, where - * the last index is (count($array) -1); any deviation from that is - * considered an associative array, and will be encoded as such. - * - * @param $array array - * @return string - */ - protected function _encodeArray(&$array) - { - $tmpArray = array(); - - // Check for associative array - if (!empty($array) && (array_keys($array) !== range(0, count($array) - 1))) { - // Associative array - $result = '{'; - foreach ($array as $key => $value) { - $key = (string) $key; - $tmpArray[] = $this->_encodeString($key) - . ':' - . $this->_encodeValue($value); - } - $result .= implode(',', $tmpArray); - $result .= '}'; - } else { - // Indexed array - $result = '['; - $length = count($array); - for ($i = 0; $i < $length; $i++) { - $tmpArray[] = $this->_encodeValue($array[$i]); - } - $result .= implode(',', $tmpArray); - $result .= ']'; - } - - return $result; - } - - - /** - * JSON encode a basic data type (string, number, boolean, null) - * - * If value type is not a string, number, boolean, or null, the string - * 'null' is returned. - * - * @param $value mixed - * @return string - */ - protected function _encodeDatum(&$value) - { - $result = 'null'; - - if (is_int($value) || is_float($value)) { - $result = (string)$value; - } elseif (is_string($value)) { - $result = $this->_encodeString($value); - } elseif (is_bool($value)) { - $result = $value ? 'true' : 'false'; - } - - return $result; - } - - - /** - * JSON encode a string value by escaping characters as necessary - * - * @param $value string - * @return string - */ - protected function _encodeString(&$string) - { - // Escape these characters with a backslash: - // " \ / \n \r \t \b \f - $search = array('\\', "\n", "\t", "\r", "\b", "\f", '"'); - $replace = array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'); - $string = str_replace($search, $replace, $string); - - // Escape certain ASCII characters: - // 0x08 => \b - // 0x0c => \f - $string = str_replace(array(chr(0x08), chr(0x0C)), array('\b', '\f'), $string); - - return '"' . $string . '"'; - } - - - /** - * Encode the constants associated with the ReflectionClass - * parameter. The encoding format is based on the class2 format - * - * @param $cls ReflectionClass - * @return string Encoded constant block in class2 format - */ - private static function _encodeConstants(ReflectionClass $cls) - { - $result = "constants : {"; - $constants = $cls->getConstants(); - - $tmpArray = array(); - if (!empty($constants)) { - foreach ($constants as $key => $value) { - $tmpArray[] = "$key: " . self::encode($value); - } - - $result .= implode(', ', $tmpArray); - } - - return $result . "}"; - } - - - /** - * Encode the public methods of the ReflectionClass in the - * class2 format - * - * @param $cls ReflectionClass - * @return string Encoded method fragment - * - */ - private static function _encodeMethods(ReflectionClass $cls) - { - $methods = $cls->getMethods(); - $result = 'methods:{'; - - $started = false; - foreach ($methods as $method) { - if (! $method->isPublic() || !$method->isUserDefined()) { - continue; - } - - if ($started) { - $result .= ','; - } - $started = true; - - $result .= '' . $method->getName(). ':function('; - - if ('__construct' != $method->getName()) { - $parameters = $method->getParameters(); - $paramCount = count($parameters); - $argsStarted = false; - - $argNames = "var argNames=["; - foreach ($parameters as $param) { - if ($argsStarted) { - $result .= ','; - } - - $result .= $param->getName(); - - if ($argsStarted) { - $argNames .= ','; - } - - $argNames .= '"' . $param->getName() . '"'; - - $argsStarted = true; - } - $argNames .= "];"; - - $result .= "){" - . $argNames - . 'var result = ZAjaxEngine.invokeRemoteMethod(' - . "this, '" . $method->getName() - . "',argNames,arguments);" - . 'return(result);}'; - } else { - $result .= "){}"; - } - } - - return $result . "}"; - } - - - /** - * Encode the public properties of the ReflectionClass in the class2 - * format. - * - * @param $cls ReflectionClass - * @return string Encode properties list - * - */ - private static function _encodeVariables(ReflectionClass $cls) - { - $properties = $cls->getProperties(); - $propValues = get_class_vars($cls->getName()); - $result = "variables:{"; - $cnt = 0; - - $tmpArray = array(); - foreach ($properties as $prop) { - if (! $prop->isPublic()) { - continue; - } - - $tmpArray[] = $prop->getName() - . ':' - . self::encode($propValues[$prop->getName()]); - } - $result .= implode(',', $tmpArray); - - return $result . "}"; - } - - /** - * Encodes the given $className into the class2 model of encoding PHP - * classes into JavaScript class2 classes. - * NOTE: Currently only public methods and variables are proxied onto - * the client machine - * - * @param $className string The name of the class, the class must be - * instantiable using a null constructor - * @param $package string Optional package name appended to JavaScript - * proxy class name - * @return string The class2 (JavaScript) encoding of the class - * @throws Zend_Json_Exception - */ - public static function encodeClass($className, $package = '') - { - $cls = new ReflectionClass($className); - if (! $cls->isInstantiable()) { - throw new Zend_Json_Exception("$className must be instantiable"); - } - - return "Class.create('$package$className',{" - . self::_encodeConstants($cls) ."," - . self::_encodeMethods($cls) ."," - . self::_encodeVariables($cls) .'});'; - } - - - /** - * Encode several classes at once - * - * Returns JSON encoded classes, using {@link encodeClass()}. - * - * @param array $classNames - * @param string $package - * @return string - */ - public static function encodeClasses(array $classNames, $package = '') - { - $result = ''; - foreach ($classNames as $className) { - $result .= self::encodeClass($className, $package); - } - - return $result; - } - -} - diff --git a/phpQuery/phpQuery/Zend/Json/Exception.php b/phpQuery/phpQuery/Zend/Json/Exception.php deleted file mode 100644 index 5b99095..0000000 --- a/phpQuery/phpQuery/Zend/Json/Exception.php +++ /dev/null @@ -1,36 +0,0 @@ - $dir) { - if ($dir == '.') { - $dirs[$key] = $dirPath; - } else { - $dir = rtrim($dir, '\\/'); - $dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath; - } - } - $file = basename($file); - self::loadFile($file, $dirs, true); - } else { - self::_securityCheck($file); - include_once $file; - } - - if (!class_exists($class, false) && !interface_exists($class, false)) { - require_once 'Zend/Exception.php'; - throw new Zend_Exception("File \"$file\" does not exist or class \"$class\" was not found in the file"); - } - } - - /** - * Loads a PHP file. This is a wrapper for PHP's include() function. - * - * $filename must be the complete filename, including any - * extension such as ".php". Note that a security check is performed that - * does not permit extended characters in the filename. This method is - * intended for loading Zend Framework files. - * - * If $dirs is a string or an array, it will search the directories - * in the order supplied, and attempt to load the first matching file. - * - * If the file was not found in the $dirs, or if no $dirs were specified, - * it will attempt to load it from PHP's include_path. - * - * If $once is TRUE, it will use include_once() instead of include(). - * - * @param string $filename - * @param string|array $dirs - OPTIONAL either a path or array of paths - * to search. - * @param boolean $once - * @return boolean - * @throws Zend_Exception - */ - public static function loadFile($filename, $dirs = null, $once = false) - { - self::_securityCheck($filename); - - /** - * Search in provided directories, as well as include_path - */ - $incPath = false; - if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) { - if (is_array($dirs)) { - $dirs = implode(PATH_SEPARATOR, $dirs); - } - $incPath = get_include_path(); - set_include_path($dirs . PATH_SEPARATOR . $incPath); - } - - /** - * Try finding for the plain filename in the include_path. - */ - if ($once) { - include_once $filename; - } else { - include $filename; - } - - /** - * If searching in directories, reset include_path - */ - if ($incPath) { - set_include_path($incPath); - } - - return true; - } - - /** - * Returns TRUE if the $filename is readable, or FALSE otherwise. - * This function uses the PHP include_path, where PHP's is_readable() - * does not. - * - * @param string $filename - * @return boolean - */ - public static function isReadable($filename) - { - if (!$fh = @fopen($filename, 'r', true)) { - return false; - } - @fclose($fh); - return true; - } - - /** - * spl_autoload() suitable implementation for supporting class autoloading. - * - * Attach to spl_autoload() using the following: - * - * spl_autoload_register(array('Zend_Loader', 'autoload')); - * - * - * @param string $class - * @return string|false Class name on success; false on failure - */ - public static function autoload($class) - { - try { - self::loadClass($class); - return $class; - } catch (Exception $e) { - return false; - } - } - - /** - * Register {@link autoload()} with spl_autoload() - * - * @param string $class (optional) - * @param boolean $enabled (optional) - * @return void - * @throws Zend_Exception if spl_autoload() is not found - * or if the specified class does not have an autoload() method. - */ - public static function registerAutoload($class = 'Zend_Loader', $enabled = true) - { - if (!function_exists('spl_autoload_register')) { - require_once 'Zend/Exception.php'; - throw new Zend_Exception('spl_autoload does not exist in this PHP installation'); - } - - self::loadClass($class); - $methods = get_class_methods($class); - if (!in_array('autoload', (array) $methods)) { - require_once 'Zend/Exception.php'; - throw new Zend_Exception("The class \"$class\" does not have an autoload() method"); - } - - if ($enabled === true) { - spl_autoload_register(array($class, 'autoload')); - } else { - spl_autoload_unregister(array($class, 'autoload')); - } - } - - /** - * Ensure that filename does not contain exploits - * - * @param string $filename - * @return void - * @throws Zend_Exception - */ - protected static function _securityCheck($filename) - { - /** - * Security check - */ - if (preg_match('/[^a-z0-9\\/\\\\_.-]/i', $filename)) { - require_once 'Zend/Exception.php'; - throw new Zend_Exception('Security check: Illegal character in filename'); - } - } - - /** - * Attempt to include() the file. - * - * include() is not prefixed with the @ operator because if - * the file is loaded and contains a parse error, execution - * will halt silently and this is difficult to debug. - * - * Always set display_errors = Off on production servers! - * - * @param string $filespec - * @param boolean $once - * @return boolean - * @deprecated Since 1.5.0; use loadFile() instead - */ - protected static function _includeFile($filespec, $once = false) - { - if ($once) { - return include_once $filespec; - } else { - return include $filespec ; - } - } -} diff --git a/phpQuery/phpQuery/Zend/Registry.php b/phpQuery/phpQuery/Zend/Registry.php deleted file mode 100644 index 62d9ceb..0000000 --- a/phpQuery/phpQuery/Zend/Registry.php +++ /dev/null @@ -1,195 +0,0 @@ -offsetExists($index)) { - require_once 'Zend/Exception.php'; - throw new Zend_Exception("No entry is registered for key '$index'"); - } - - return $instance->offsetGet($index); - } - - /** - * setter method, basically same as offsetSet(). - * - * This method can be called from an object of type Zend_Registry, or it - * can be called statically. In the latter case, it uses the default - * static instance stored in the class. - * - * @param string $index The location in the ArrayObject in which to store - * the value. - * @param mixed $value The object to store in the ArrayObject. - * @return void - */ - public static function set($index, $value) - { - $instance = self::getInstance(); - $instance->offsetSet($index, $value); - } - - /** - * Returns TRUE if the $index is a named value in the registry, - * or FALSE if $index was not found in the registry. - * - * @param string $index - * @return boolean - */ - public static function isRegistered($index) - { - if (self::$_registry === null) { - return false; - } - return self::$_registry->offsetExists($index); - } - - /** - * @param string $index - * @returns mixed - * - * Workaround for http://bugs.php.net/bug.php?id=40442 (ZF-960). - */ - public function offsetExists($index) - { - return array_key_exists($index, $this); - } - -} diff --git a/phpQuery/phpQuery/Zend/Uri.php b/phpQuery/phpQuery/Zend/Uri.php deleted file mode 100644 index 4c5776b..0000000 --- a/phpQuery/phpQuery/Zend/Uri.php +++ /dev/null @@ -1,164 +0,0 @@ -getUri(); - } - - /** - * Convenience function, checks that a $uri string is well-formed - * by validating it but not returning an object. Returns TRUE if - * $uri is a well-formed URI, or FALSE otherwise. - * - * @param string $uri The URI to check - * @return boolean - */ - public static function check($uri) - { - try { - $uri = self::factory($uri); - } catch (Exception $e) { - return false; - } - - return $uri->valid(); - } - - /** - * Create a new Zend_Uri object for a URI. If building a new URI, then $uri should contain - * only the scheme (http, ftp, etc). Otherwise, supply $uri with the complete URI. - * - * @param string $uri The URI form which a Zend_Uri instance is created - * @throws Zend_Uri_Exception When an empty string was supplied for the scheme - * @throws Zend_Uri_Exception When an illegal scheme is supplied - * @throws Zend_Uri_Exception When the scheme is not supported - * @return Zend_Uri - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public static function factory($uri = 'http') - { - // Separate the scheme from the scheme-specific parts - $uri = explode(':', $uri, 2); - $scheme = strtolower($uri[0]); - $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; - - if (strlen($scheme) === 0) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('An empty string was supplied for the scheme'); - } - - // Security check: $scheme is used to load a class file, so only alphanumerics are allowed. - if (ctype_alnum($scheme) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Illegal scheme supplied, only alphanumeric characters are permitted'); - } - - /** - * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the - * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown. - */ - switch ($scheme) { - case 'http': - // Break intentionally omitted - case 'https': - $className = 'Zend_Uri_Http'; - break; - - case 'mailto': - // TODO - default: - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("Scheme \"$scheme\" is not supported"); - break; - } - - Zend_Loader::loadClass($className); - $schemeHandler = new $className($scheme, $schemeSpecific); - - return $schemeHandler; - } - - /** - * Get the URI's scheme - * - * @return string|false Scheme or false if no scheme is set. - */ - public function getScheme() - { - if (empty($this->_scheme) === false) { - return $this->_scheme; - } else { - return false; - } - } - - /** - * Zend_Uri and its subclasses cannot be instantiated directly. - * Use Zend_Uri::factory() to return a new Zend_Uri object. - * - * @param string $scheme The scheme of the URI - * @param string $schemeSpecific The scheme-specific part of the URI - */ - abstract protected function __construct($scheme, $schemeSpecific = ''); - - /** - * Return a string representation of this URI. - * - * @return string - */ - abstract public function getUri(); - - /** - * Returns TRUE if this URI is valid, or FALSE otherwise. - * - * @return boolean - */ - abstract public function valid(); -} diff --git a/phpQuery/phpQuery/Zend/Uri/Exception.php b/phpQuery/phpQuery/Zend/Uri/Exception.php deleted file mode 100644 index d327f3c..0000000 --- a/phpQuery/phpQuery/Zend/Uri/Exception.php +++ /dev/null @@ -1,37 +0,0 @@ -_scheme = $scheme; - - // Set up grammar rules for validation via regular expressions. These - // are to be used with slash-delimited regular expression strings. - $this->_regex['alphanum'] = '[^\W_]'; - $this->_regex['escaped'] = '(?:%[\da-fA-F]{2})'; - $this->_regex['mark'] = '[-_.!~*\'()\[\]]'; - $this->_regex['reserved'] = '[;\/?:@&=+$,]'; - $this->_regex['unreserved'] = '(?:' . $this->_regex['alphanum'] . '|' . $this->_regex['mark'] . ')'; - $this->_regex['segment'] = '(?:(?:' . $this->_regex['unreserved'] . '|' . $this->_regex['escaped'] - . '|[:@&=+$,;])*)'; - $this->_regex['path'] = '(?:\/' . $this->_regex['segment'] . '?)+'; - $this->_regex['uric'] = '(?:' . $this->_regex['reserved'] . '|' . $this->_regex['unreserved'] . '|' - . $this->_regex['escaped'] . ')'; - // If no scheme-specific part was supplied, the user intends to create - // a new URI with this object. No further parsing is required. - if (strlen($schemeSpecific) === 0) { - return; - } - - // Parse the scheme-specific URI parts into the instance variables. - $this->_parseUri($schemeSpecific); - - // Validate the URI - if ($this->valid() === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Invalid URI supplied'); - } - } - - /** - * Creates a Zend_Uri_Http from the given string - * - * @param string $uri String to create URI from, must start with - * 'http://' or 'https://' - * @throws InvalidArgumentException When the given $uri is not a string or - * does not start with http:// or https:// - * @throws Zend_Uri_Exception When the given $uri is invalid - * @return Zend_Uri_Http - */ - public static function fromString($uri) - { - if (is_string($uri) === false) { - throw new InvalidArgumentException('$uri is not a string'); - } - - $uri = explode(':', $uri, 2); - $scheme = strtolower($uri[0]); - $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; - - if (in_array($scheme, array('http', 'https')) === false) { - throw new Zend_Uri_Exception("Invalid scheme: '$scheme'"); - } - - $schemeHandler = new Zend_Uri_Http($scheme, $schemeSpecific); - return $schemeHandler; - } - - /** - * Parse the scheme-specific portion of the URI and place its parts into instance variables. - * - * @param string $schemeSpecific The scheme-specific portion to parse - * @throws Zend_Uri_Exception When scheme-specific decoposition fails - * @throws Zend_Uri_Exception When authority decomposition fails - * @return void - */ - protected function _parseUri($schemeSpecific) - { - // High-level decomposition parser - $pattern = '~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~'; - $status = @preg_match($pattern, $schemeSpecific, $matches); - if ($status === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Internal error: scheme-specific decomposition failed'); - } - - // Failed decomposition; no further processing needed - if ($status === false) { - return; - } - - // Save URI components that need no further decomposition - $this->_path = isset($matches[4]) === true ? $matches[4] : ''; - $this->_query = isset($matches[6]) === true ? $matches[6] : ''; - $this->_fragment = isset($matches[8]) === true ? $matches[8] : ''; - - // Additional decomposition to get username, password, host, and port - $combo = isset($matches[3]) === true ? $matches[3] : ''; - $pattern = '~^(([^:@]*)(:([^@]*))?@)?([^:]+)(:(.*))?$~'; - $status = @preg_match($pattern, $combo, $matches); - if ($status === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Internal error: authority decomposition failed'); - } - - // Failed decomposition; no further processing needed - if ($status === false) { - return; - } - - // Save remaining URI components - $this->_username = isset($matches[2]) === true ? $matches[2] : ''; - $this->_password = isset($matches[4]) === true ? $matches[4] : ''; - $this->_host = isset($matches[5]) === true ? $matches[5] : ''; - $this->_port = isset($matches[7]) === true ? $matches[7] : ''; - - } - - /** - * Returns a URI based on current values of the instance variables. If any - * part of the URI does not pass validation, then an exception is thrown. - * - * @throws Zend_Uri_Exception When one or more parts of the URI are invalid - * @return string - */ - public function getUri() - { - if ($this->valid() === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('One or more parts of the URI are invalid'); - } - - $password = strlen($this->_password) > 0 ? ":$this->_password" : ''; - $auth = strlen($this->_username) > 0 ? "$this->_username$password@" : ''; - $port = strlen($this->_port) > 0 ? ":$this->_port" : ''; - $query = strlen($this->_query) > 0 ? "?$this->_query" : ''; - $fragment = strlen($this->_fragment) > 0 ? "#$this->_fragment" : ''; - - return $this->_scheme - . '://' - . $auth - . $this->_host - . $port - . $this->_path - . $query - . $fragment; - } - - /** - * Validate the current URI from the instance variables. Returns true if and only if all - * parts pass validation. - * - * @return boolean - */ - public function valid() - { - // Return true if and only if all parts of the URI have passed validation - return $this->validateUsername() - and $this->validatePassword() - and $this->validateHost() - and $this->validatePort() - and $this->validatePath() - and $this->validateQuery() - and $this->validateFragment(); - } - - /** - * Returns the username portion of the URL, or FALSE if none. - * - * @return string - */ - public function getUsername() - { - return strlen($this->_username) > 0 ? $this->_username : false; - } - - /** - * Returns true if and only if the username passes validation. If no username is passed, - * then the username contained in the instance variable is used. - * - * @param string $username The HTTP username - * @throws Zend_Uri_Exception When username validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validateUsername($username = null) - { - if ($username === null) { - $username = $this->_username; - } - - // If the username is empty, then it is considered valid - if (strlen($username) === 0) { - return true; - } - - // Check the username against the allowed values - $status = @preg_match('/^(' . $this->_regex['alphanum'] . '|' . $this->_regex['mark'] . '|' - . $this->_regex['escaped'] . '|[;:&=+$,])+$/', $username); - if ($status === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Internal error: username validation failed'); - } - - return $status === 1; - } - - /** - * Sets the username for the current URI, and returns the old username - * - * @param string $username The HTTP username - * @throws Zend_Uri_Exception When $username is not a valid HTTP username - * @return string - */ - public function setUsername($username) - { - if ($this->validateUsername($username) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("Username \"$username\" is not a valid HTTP username"); - } - - $oldUsername = $this->_username; - $this->_username = $username; - - return $oldUsername; - } - - /** - * Returns the password portion of the URL, or FALSE if none. - * - * @return string - */ - public function getPassword() - { - return strlen($this->_password) > 0 ? $this->_password : false; - } - - /** - * Returns true if and only if the password passes validation. If no password is passed, - * then the password contained in the instance variable is used. - * - * @param string $password The HTTP password - * @throws Zend_Uri_Exception When password validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validatePassword($password = null) - { - if ($password === null) { - $password = $this->_password; - } - - // If the password is empty, then it is considered valid - if (strlen($password) === 0) { - return true; - } - - // If the password is nonempty, but there is no username, then it is considered invalid - if (strlen($password) > 0 and strlen($this->_username) === 0) { - return false; - } - - // Check the password against the allowed values - $status = @preg_match('/^(' . $this->_regex['alphanum'] . '|' . $this->_regex['mark'] . '|' - . $this->_regex['escaped'] . '|[;:&=+$,])+$/', $password); - if ($status === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Internal error: password validation failed.'); - } - - return $status == 1; - } - - /** - * Sets the password for the current URI, and returns the old password - * - * @param string $password The HTTP password - * @throws Zend_Uri_Exception When $password is not a valid HTTP password - * @return string - */ - public function setPassword($password) - { - if ($this->validatePassword($password) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("Password \"$password\" is not a valid HTTP password."); - } - - $oldPassword = $this->_password; - $this->_password = $password; - - return $oldPassword; - } - - /** - * Returns the domain or host IP portion of the URL, or FALSE if none. - * - * @return string - */ - public function getHost() - { - return strlen($this->_host) > 0 ? $this->_host : false; - } - - /** - * Returns true if and only if the host string passes validation. If no host is passed, - * then the host contained in the instance variable is used. - * - * @param string $host The HTTP host - * @return boolean - * @uses Zend_Filter - */ - public function validateHost($host = null) - { - if ($host === null) { - $host = $this->_host; - } - - // If the host is empty, then it is considered invalid - if (strlen($host) === 0) { - return false; - } - - // Check the host against the allowed values; delegated to Zend_Filter. - $validate = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL); - - return $validate->isValid($host); - } - - /** - * Sets the host for the current URI, and returns the old host - * - * @param string $host The HTTP host - * @throws Zend_Uri_Exception When $host is nota valid HTTP host - * @return string - */ - public function setHost($host) - { - if ($this->validateHost($host) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("Host \"$host\" is not a valid HTTP host"); - } - - $oldHost = $this->_host; - $this->_host = $host; - - return $oldHost; - } - - /** - * Returns the TCP port, or FALSE if none. - * - * @return string - */ - public function getPort() - { - return strlen($this->_port) > 0 ? $this->_port : false; - } - - /** - * Returns true if and only if the TCP port string passes validation. If no port is passed, - * then the port contained in the instance variable is used. - * - * @param string $port The HTTP port - * @return boolean - */ - public function validatePort($port = null) - { - if ($port === null) { - $port = $this->_port; - } - - // If the port is empty, then it is considered valid - if (strlen($port) === 0) { - return true; - } - - // Check the port against the allowed values - return ctype_digit((string) $port) and 1 <= $port and $port <= 65535; - } - - /** - * Sets the port for the current URI, and returns the old port - * - * @param string $port The HTTP port - * @throws Zend_Uri_Exception When $port is not a valid HTTP port - * @return string - */ - public function setPort($port) - { - if ($this->validatePort($port) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("Port \"$port\" is not a valid HTTP port."); - } - - $oldPort = $this->_port; - $this->_port = $port; - - return $oldPort; - } - - /** - * Returns the path and filename portion of the URL, or FALSE if none. - * - * @return string - */ - public function getPath() - { - return strlen($this->_path) > 0 ? $this->_path : '/'; - } - - /** - * Returns true if and only if the path string passes validation. If no path is passed, - * then the path contained in the instance variable is used. - * - * @param string $path The HTTP path - * @throws Zend_Uri_Exception When path validation fails - * @return boolean - */ - public function validatePath($path = null) - { - if ($path === null) { - $path = $this->_path; - } - - // If the path is empty, then it is considered valid - if (strlen($path) === 0) { - return true; - } - - // Determine whether the path is well-formed - $pattern = '/^' . $this->_regex['path'] . '$/'; - $status = @preg_match($pattern, $path); - if ($status === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Internal error: path validation failed'); - } - - return (boolean) $status; - } - - /** - * Sets the path for the current URI, and returns the old path - * - * @param string $path The HTTP path - * @throws Zend_Uri_Exception When $path is not a valid HTTP path - * @return string - */ - public function setPath($path) - { - if ($this->validatePath($path) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("Path \"$path\" is not a valid HTTP path"); - } - - $oldPath = $this->_path; - $this->_path = $path; - - return $oldPath; - } - - /** - * Returns the query portion of the URL (after ?), or FALSE if none. - * - * @return string - */ - public function getQuery() - { - return strlen($this->_query) > 0 ? $this->_query : false; - } - - /** - * Returns true if and only if the query string passes validation. If no query is passed, - * then the query string contained in the instance variable is used. - * - * @param string $query The query to validate - * @throws Zend_Uri_Exception When query validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validateQuery($query = null) - { - if ($query === null) { - $query = $this->_query; - } - - // If query is empty, it is considered to be valid - if (strlen($query) === 0) { - return true; - } - - // Determine whether the query is well-formed - $pattern = '/^' . $this->_regex['uric'] . '*$/'; - $status = @preg_match($pattern, $query); - if ($status === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Internal error: query validation failed'); - } - - return $status == 1; - } - - /** - * Set the query string for the current URI, and return the old query - * string This method accepts both strings and arrays. - * - * @param string|array $query The query string or array - * @throws Zend_Uri_Exception When $query is not a valid query string - * @return string Old query string - */ - public function setQuery($query) - { - $oldQuery = $this->_query; - - // If query is empty, set an empty string - if (empty($query) === true) { - $this->_query = ''; - return $oldQuery; - } - - // If query is an array, make a string out of it - if (is_array($query) === true) { - $query = http_build_query($query, '', '&'); - } else { - // If it is a string, make sure it is valid. If not parse and encode it - $query = (string) $query; - if ($this->validateQuery($query) === false) { - parse_str($query, $queryArray); - $query = http_build_query($queryArray, '', '&'); - } - } - - // Make sure the query is valid, and set it - if ($this->validateQuery($query) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("'$query' is not a valid query string"); - } - - $this->_query = $query; - - return $oldQuery; - } - - /** - * Returns the fragment portion of the URL (after #), or FALSE if none. - * - * @return string|false - */ - public function getFragment() - { - return strlen($this->_fragment) > 0 ? $this->_fragment : false; - } - - /** - * Returns true if and only if the fragment passes validation. If no fragment is passed, - * then the fragment contained in the instance variable is used. - * - * @param string $fragment Fragment of an URI - * @throws Zend_Uri_Exception When fragment validation fails - * @return boolean - * @link http://www.faqs.org/rfcs/rfc2396.html - */ - public function validateFragment($fragment = null) - { - if ($fragment === null) { - $fragment = $this->_fragment; - } - - // If fragment is empty, it is considered to be valid - if (strlen($fragment) === 0) { - return true; - } - - // Determine whether the fragment is well-formed - $pattern = '/^' . $this->_regex['uric'] . '*$/'; - $status = @preg_match($pattern, $fragment); - if ($status === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception('Internal error: fragment validation failed'); - } - - return (boolean) $status; - } - - /** - * Sets the fragment for the current URI, and returns the old fragment - * - * @param string $fragment Fragment of the current URI - * @throws Zend_Uri_Exception When $fragment is not a valid HTTP fragment - * @return string - */ - public function setFragment($fragment) - { - if ($this->validateFragment($fragment) === false) { - require_once 'Zend/Uri/Exception.php'; - throw new Zend_Uri_Exception("Fragment \"$fragment\" is not a valid HTTP fragment"); - } - - $oldFragment = $this->_fragment; - $this->_fragment = $fragment; - - return $oldFragment; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/Abstract.php b/phpQuery/phpQuery/Zend/Validate/Abstract.php deleted file mode 100644 index 1c11d54..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Abstract.php +++ /dev/null @@ -1,348 +0,0 @@ -_messages; - } - - /** - * Returns an array of the names of variables that are used in constructing validation failure messages - * - * @return array - */ - public function getMessageVariables() - { - return array_keys($this->_messageVariables); - } - - /** - * Sets the validation failure message template for a particular key - * - * @param string $messageString - * @param string $messageKey OPTIONAL - * @return Zend_Validate_Abstract Provides a fluent interface - * @throws Zend_Validate_Exception - */ - public function setMessage($messageString, $messageKey = null) - { - if ($messageKey === null) { - $keys = array_keys($this->_messageTemplates); - $messageKey = current($keys); - } - if (!isset($this->_messageTemplates[$messageKey])) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("No message template exists for key '$messageKey'"); - } - $this->_messageTemplates[$messageKey] = $messageString; - return $this; - } - - /** - * Sets validation failure message templates given as an array, where the array keys are the message keys, - * and the array values are the message template strings. - * - * @param array $messages - * @return Zend_Validate_Abstract - */ - public function setMessages(array $messages) - { - foreach ($messages as $key => $message) { - $this->setMessage($message, $key); - } - return $this; - } - - /** - * Magic function returns the value of the requested property, if and only if it is the value or a - * message variable. - * - * @param string $property - * @return mixed - * @throws Zend_Validate_Exception - */ - public function __get($property) - { - if ($property == 'value') { - return $this->_value; - } - if (array_key_exists($property, $this->_messageVariables)) { - return $this->{$this->_messageVariables[$property]}; - } - /** - * @see Zend_Validate_Exception - */ - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("No property exists by the name '$property'"); - } - - /** - * Constructs and returns a validation failure message with the given message key and value. - * - * Returns null if and only if $messageKey does not correspond to an existing template. - * - * If a translator is available and a translation exists for $messageKey, - * the translation will be used. - * - * @param string $messageKey - * @param string $value - * @return string - */ - protected function _createMessage($messageKey, $value) - { - if (!isset($this->_messageTemplates[$messageKey])) { - return null; - } - - $message = $this->_messageTemplates[$messageKey]; - - if (null !== ($translator = $this->getTranslator())) { - if ($translator->isTranslated($message)) { - $message = $translator->translate($message); - } elseif ($translator->isTranslated($messageKey)) { - $message = $translator->translate($messageKey); - } - } - - if ($this->getObscureValue()) { - $value = str_repeat('*', strlen($value)); - } - - $message = str_replace('%value%', (string) $value, $message); - foreach ($this->_messageVariables as $ident => $property) { - $message = str_replace("%$ident%", $this->$property, $message); - } - return $message; - } - - /** - * @param string $messageKey OPTIONAL - * @param string $value OPTIONAL - * @return void - */ - protected function _error($messageKey = null, $value = null) - { - if ($messageKey === null) { - $keys = array_keys($this->_messageTemplates); - $messageKey = current($keys); - } - if ($value === null) { - $value = $this->_value; - } - $this->_errors[] = $messageKey; - $this->_messages[$messageKey] = $this->_createMessage($messageKey, $value); - } - - /** - * Sets the value to be validated and clears the messages and errors arrays - * - * @param mixed $value - * @return void - */ - protected function _setValue($value) - { - $this->_value = $value; - $this->_messages = array(); - $this->_errors = array(); - } - - /** - * Returns array of validation failure message codes - * - * @return array - * @deprecated Since 1.5.0 - */ - public function getErrors() - { - return $this->_errors; - } - - /** - * Set flag indicating whether or not value should be obfuscated in messages - * - * @param bool $flag - * @return Zend_Validate_Abstract - */ - public function setObscureValue($flag) - { - $this->_obscureValue = (bool) $flag; - return $this; - } - - /** - * Retrieve flag indicating whether or not value should be obfuscated in - * messages - * - * @return bool - */ - public function getObscureValue() - { - return $this->_obscureValue; - } - - /** - * Set translation object - * - * @param Zend_Translate|Zend_Translate_Adapter|null $translator - * @return Zend_Validate_Abstract - */ - public function setTranslator($translator = null) - { - if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { - $this->_translator = $translator; - } elseif ($translator instanceof Zend_Translate) { - $this->_translator = $translator->getAdapter(); - } else { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception('Invalid translator specified'); - } - return $this; - } - - /** - * Return translation object - * - * @return Zend_Translate_Adapter|null - */ - public function getTranslator() - { - if (null === $this->_translator) { - return self::getDefaultTranslator(); - } - - return $this->_translator; - } - - /** - * Set default translation object for all validate objects - * - * @param Zend_Translate|Zend_Translate_Adapter|null $translator - * @return void - */ - public static function setDefaultTranslator($translator = null) - { - if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { - self::$_defaultTranslator = $translator; - } elseif ($translator instanceof Zend_Translate) { - self::$_defaultTranslator = $translator->getAdapter(); - } else { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception('Invalid translator specified'); - } - } - - /** - * Get default translation object for all validate objects - * - * @return Zend_Translate_Adapter|null - */ - public static function getDefaultTranslator() - { - if (null === self::$_defaultTranslator) { - require_once 'Zend/Registry.php'; - if (Zend_Registry::isRegistered('Zend_Translate')) { - $translator = Zend_Registry::get('Zend_Translate'); - if ($translator instanceof Zend_Translate_Adapter) { - return $translator; - } elseif ($translator instanceof Zend_Translate) { - return $translator->getAdapter(); - } - } - } - return self::$_defaultTranslator; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/Alnum.php b/phpQuery/phpQuery/Zend/Validate/Alnum.php deleted file mode 100644 index 36b0adc..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Alnum.php +++ /dev/null @@ -1,120 +0,0 @@ - "'%value%' has not only alphabetic and digit characters", - self::STRING_EMPTY => "'%value%' is an empty string" - ); - - /** - * Sets default option values for this instance - * - * @param boolean $allowWhiteSpace - * @return void - */ - public function __construct($allowWhiteSpace = false) - { - $this->allowWhiteSpace = (boolean) $allowWhiteSpace; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value contains only alphabetic and digit characters - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - if ('' === $valueString) { - $this->_error(self::STRING_EMPTY); - return false; - } - - if (null === self::$_filter) { - /** - * @see Zend_Filter_Alnum - */ - require_once 'Zend/Filter/Alnum.php'; - self::$_filter = new Zend_Filter_Alnum(); - } - - self::$_filter->allowWhiteSpace = $this->allowWhiteSpace; - - if ($valueString !== self::$_filter->filter($valueString)) { - $this->_error(self::NOT_ALNUM); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Alpha.php b/phpQuery/phpQuery/Zend/Validate/Alpha.php deleted file mode 100644 index 0f2298e..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Alpha.php +++ /dev/null @@ -1,120 +0,0 @@ - "'%value%' has not only alphabetic characters", - self::STRING_EMPTY => "'%value%' is an empty string" - ); - - /** - * Sets default option values for this instance - * - * @param boolean $allowWhiteSpace - * @return void - */ - public function __construct($allowWhiteSpace = false) - { - $this->allowWhiteSpace = (boolean) $allowWhiteSpace; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value contains only alphabetic characters - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - if ('' === $valueString) { - $this->_error(self::STRING_EMPTY); - return false; - } - - if (null === self::$_filter) { - /** - * @see Zend_Filter_Alpha - */ - require_once 'Zend/Filter/Alpha.php'; - self::$_filter = new Zend_Filter_Alpha(); - } - - self::$_filter->allowWhiteSpace = $this->allowWhiteSpace; - - if ($valueString !== self::$_filter->filter($valueString)) { - $this->_error(self::NOT_ALPHA); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Barcode.php b/phpQuery/phpQuery/Zend/Validate/Barcode.php deleted file mode 100644 index d51f11b..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Barcode.php +++ /dev/null @@ -1,99 +0,0 @@ -setType($barcodeType); - } - - /** - * Sets a new barcode validator - * - * @param string $barcodeType - Barcode validator to use - * @return void - * @throws Zend_Validate_Exception - */ - public function setType($barcodeType) - { - switch (strtolower($barcodeType)) { - case 'upc': - case 'upc-a': - $className = 'UpcA'; - break; - case 'ean13': - case 'ean-13': - $className = 'Ean13'; - break; - default: - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("Barcode type '$barcodeType' is not supported'"); - break; - } - - require_once 'Zend/Validate/Barcode/' . $className . '.php'; - - $class = 'Zend_Validate_Barcode_' . $className; - $this->_barcodeValidator = new $class; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value contains a valid barcode - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - return call_user_func(array($this->_barcodeValidator, 'isValid'), $value); - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/Barcode/Ean13.php b/phpQuery/phpQuery/Zend/Validate/Barcode/Ean13.php deleted file mode 100644 index 7be797d..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Barcode/Ean13.php +++ /dev/null @@ -1,100 +0,0 @@ - "'%value%' is an invalid EAN-13 barcode", - self::INVALID_LENGTH => "'%value%' should be 13 characters", - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value contains a valid barcode - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - $this->_setValue($valueString); - - if (strlen($valueString) !== 13) { - $this->_error(self::INVALID_LENGTH); - return false; - } - - $barcode = strrev(substr($valueString, 0, -1)); - $oddSum = 0; - $evenSum = 0; - - for ($i = 0; $i < 12; $i++) { - if ($i % 2 === 0) { - $oddSum += $barcode[$i] * 3; - } elseif ($i % 2 === 1) { - $evenSum += $barcode[$i]; - } - } - - $calculation = ($oddSum + $evenSum) % 10; - $checksum = ($calculation === 0) ? 0 : 10 - $calculation; - - if ($valueString[12] != $checksum) { - $this->_error(self::INVALID); - return false; - } - - return true; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/Barcode/UpcA.php b/phpQuery/phpQuery/Zend/Validate/Barcode/UpcA.php deleted file mode 100644 index c584e81..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Barcode/UpcA.php +++ /dev/null @@ -1,100 +0,0 @@ - "'%value%' is an invalid UPC-A barcode", - self::INVALID_LENGTH => "'%value%' should be 12 characters", - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value contains a valid barcode - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - $this->_setValue($valueString); - - if (strlen($valueString) !== 12) { - $this->_error(self::INVALID_LENGTH); - return false; - } - - $barcode = substr($valueString, 0, -1); - $oddSum = 0; - $evenSum = 0; - - for ($i = 0; $i < 11; $i++) { - if ($i % 2 === 0) { - $oddSum += $barcode[$i] * 3; - } elseif ($i % 2 === 1) { - $evenSum += $barcode[$i]; - } - } - - $calculation = ($oddSum + $evenSum) % 10; - $checksum = ($calculation === 0) ? 0 : 10 - $calculation; - - if ($valueString[11] != $checksum) { - $this->_error(self::INVALID); - return false; - } - - return true; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/Between.php b/phpQuery/phpQuery/Zend/Validate/Between.php deleted file mode 100644 index bb0b726..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Between.php +++ /dev/null @@ -1,200 +0,0 @@ - "'%value%' is not between '%min%' and '%max%', inclusively", - self::NOT_BETWEEN_STRICT => "'%value%' is not strictly between '%min%' and '%max%'" - ); - - /** - * Additional variables available for validation failure messages - * - * @var array - */ - protected $_messageVariables = array( - 'min' => '_min', - 'max' => '_max' - ); - - /** - * Minimum value - * - * @var mixed - */ - protected $_min; - - /** - * Maximum value - * - * @var mixed - */ - protected $_max; - - /** - * Whether to do inclusive comparisons, allowing equivalence to min and/or max - * - * If false, then strict comparisons are done, and the value may equal neither - * the min nor max options - * - * @var boolean - */ - protected $_inclusive; - - /** - * Sets validator options - * - * @param mixed $min - * @param mixed $max - * @param boolean $inclusive - * @return void - */ - public function __construct($min, $max, $inclusive = true) - { - $this->setMin($min) - ->setMax($max) - ->setInclusive($inclusive); - } - - /** - * Returns the min option - * - * @return mixed - */ - public function getMin() - { - return $this->_min; - } - - /** - * Sets the min option - * - * @param mixed $min - * @return Zend_Validate_Between Provides a fluent interface - */ - public function setMin($min) - { - $this->_min = $min; - return $this; - } - - /** - * Returns the max option - * - * @return mixed - */ - public function getMax() - { - return $this->_max; - } - - /** - * Sets the max option - * - * @param mixed $max - * @return Zend_Validate_Between Provides a fluent interface - */ - public function setMax($max) - { - $this->_max = $max; - return $this; - } - - /** - * Returns the inclusive option - * - * @return boolean - */ - public function getInclusive() - { - return $this->_inclusive; - } - - /** - * Sets the inclusive option - * - * @param boolean $inclusive - * @return Zend_Validate_Between Provides a fluent interface - */ - public function setInclusive($inclusive) - { - $this->_inclusive = $inclusive; - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is between min and max options, inclusively - * if inclusive option is true. - * - * @param mixed $value - * @return boolean - */ - public function isValid($value) - { - $this->_setValue($value); - - if ($this->_inclusive) { - if ($this->_min > $value || $value > $this->_max) { - $this->_error(self::NOT_BETWEEN); - return false; - } - } else { - if ($this->_min >= $value || $value >= $this->_max) { - $this->_error(self::NOT_BETWEEN_STRICT); - return false; - } - } - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Ccnum.php b/phpQuery/phpQuery/Zend/Validate/Ccnum.php deleted file mode 100644 index 227a4ec..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Ccnum.php +++ /dev/null @@ -1,111 +0,0 @@ - "'%value%' must contain between 13 and 19 digits", - self::CHECKSUM => "Luhn algorithm (mod-10 checksum) failed on '%value%'" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value follows the Luhn algorithm (mod-10 checksum) - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $this->_setValue($value); - - if (null === self::$_filter) { - /** - * @see Zend_Filter_Digits - */ - require_once 'Zend/Filter/Digits.php'; - self::$_filter = new Zend_Filter_Digits(); - } - - $valueFiltered = self::$_filter->filter($value); - - $length = strlen($valueFiltered); - - if ($length < 13 || $length > 19) { - $this->_error(self::LENGTH); - return false; - } - - $sum = 0; - $weight = 2; - - for ($i = $length - 2; $i >= 0; $i--) { - $digit = $weight * $valueFiltered[$i]; - $sum += floor($digit / 10) + $digit % 10; - $weight = $weight % 2 + 1; - } - - if ((10 - $sum % 10) % 10 != $valueFiltered[$length - 1]) { - $this->_error(self::CHECKSUM, $valueFiltered); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Date.php b/phpQuery/phpQuery/Zend/Validate/Date.php deleted file mode 100644 index 220b0ee..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Date.php +++ /dev/null @@ -1,250 +0,0 @@ - "'%value%' is not of the format YYYY-MM-DD", - self::INVALID => "'%value%' does not appear to be a valid date", - self::FALSEFORMAT => "'%value%' does not fit given date format" - ); - - /** - * Optional format - * - * @var string|null - */ - protected $_format; - - /** - * Optional locale - * - * @var string|Zend_Locale|null - */ - protected $_locale; - - /** - * Sets validator options - * - * @param string $format OPTIONAL - * @param string|Zend_Locale $locale OPTIONAL - * @return void - */ - public function __construct($format = null, $locale = null) - { - $this->setFormat($format); - $this->setLocale($locale); - } - - /** - * Returns the locale option - * - * @return string|Zend_Locale|null - */ - public function getLocale() - { - return $this->_locale; - } - - /** - * Sets the locale option - * - * @param string|Zend_Locale $locale - * @return Zend_Validate_Date provides a fluent interface - */ - public function setLocale($locale = null) - { - if ($locale === null) { - $this->_locale = null; - return $this; - } - - require_once 'Zend/Locale.php'; - if (!Zend_Locale::isLocale($locale, true)) { - if (!Zend_Locale::isLocale($locale, false)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The locale '$locale' is no known locale"); - } - - $locale = new Zend_Locale($locale); - } - - $this->_locale = (string) $locale; - return $this; - } - - /** - * Returns the locale option - * - * @return string|null - */ - public function getFormat() - { - return $this->_format; - } - - /** - * Sets the format option - * - * @param string $format - * @return Zend_Validate_Date provides a fluent interface - */ - public function setFormat($format = null) - { - $this->_format = $format; - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if $value is a valid date of the format YYYY-MM-DD - * If optional $format or $locale is set the date format is checked - * according to Zend_Date, see Zend_Date::isDate() - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - if (($this->_format !== null) or ($this->_locale !== null)) { - require_once 'Zend/Date.php'; - if (!Zend_Date::isDate($value, $this->_format, $this->_locale)) { - if ($this->_checkFormat($value) === false) { - $this->_error(self::FALSEFORMAT); - } else { - $this->_error(self::INVALID); - } - return false; - } - } else { - if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $valueString)) { - $this->_error(self::NOT_YYYY_MM_DD); - return false; - } - - list($year, $month, $day) = sscanf($valueString, '%d-%d-%d'); - - if (!checkdate($month, $day, $year)) { - $this->_error(self::INVALID); - return false; - } - } - - return true; - } - - /** - * Check if the given date fits the given format - * - * @param string $value Date to check - * @return boolean False when date does not fit the format - */ - private function _checkFormat($value) - { - try { - require_once 'Zend/Locale/Format.php'; - $parsed = Zend_Locale_Format::getDate($value, array( - 'date_format' => $this->_format, 'format_type' => 'iso', - 'fix_date' => false)); - if (isset($parsed['year']) and ((strpos(strtoupper($this->_format), 'YY') !== false) and - (strpos(strtoupper($this->_format), 'YYYY') === false))) { - $parsed['year'] = Zend_Date::_century($parsed['year']); - } - } catch (Exception $e) { - // Date can not be parsed - return false; - } - - if (((strpos($this->_format, 'Y') !== false) or (strpos($this->_format, 'y') !== false)) and - (!isset($parsed['year']))) { - // Year expected but not found - return false; - } - - if ((strpos($this->_format, 'M') !== false) and (!isset($parsed['month']))) { - // Month expected but not found - return false; - } - - if ((strpos($this->_format, 'd') !== false) and (!isset($parsed['day']))) { - // Day expected but not found - return false; - } - - if (((strpos($this->_format, 'H') !== false) or (strpos($this->_format, 'h') !== false)) and - (!isset($parsed['hour']))) { - // Hour expected but not found - return false; - } - - if ((strpos($this->_format, 'm') !== false) and (!isset($parsed['minute']))) { - // Minute expected but not found - return false; - } - - if ((strpos($this->_format, 's') !== false) and (!isset($parsed['second']))) { - // Second expected but not found - return false; - } - - // Date fits the format - return true; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/Digits.php b/phpQuery/phpQuery/Zend/Validate/Digits.php deleted file mode 100644 index c42ec0a..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Digits.php +++ /dev/null @@ -1,100 +0,0 @@ - "'%value%' contains not only digit characters", - self::STRING_EMPTY => "'%value%' is an empty string" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value only contains digit characters - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - if ('' === $valueString) { - $this->_error(self::STRING_EMPTY); - return false; - } - - if (null === self::$_filter) { - /** - * @see Zend_Filter_Digits - */ - require_once 'Zend/Filter/Digits.php'; - self::$_filter = new Zend_Filter_Digits(); - } - - if ($valueString !== self::$_filter->filter($valueString)) { - $this->_error(self::NOT_DIGITS); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/EmailAddress.php b/phpQuery/phpQuery/Zend/Validate/EmailAddress.php deleted file mode 100644 index d8e9595..0000000 --- a/phpQuery/phpQuery/Zend/Validate/EmailAddress.php +++ /dev/null @@ -1,245 +0,0 @@ - "'%value%' is not a valid email address in the basic format local-part@hostname", - self::INVALID_HOSTNAME => "'%hostname%' is not a valid hostname for email address '%value%'", - self::INVALID_MX_RECORD => "'%hostname%' does not appear to have a valid MX record for the email address '%value%'", - self::DOT_ATOM => "'%localPart%' not matched against dot-atom format", - self::QUOTED_STRING => "'%localPart%' not matched against quoted-string format", - self::INVALID_LOCAL_PART => "'%localPart%' is not a valid local part for email address '%value%'" - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'hostname' => '_hostname', - 'localPart' => '_localPart' - ); - - /** - * Local object for validating the hostname part of an email address - * - * @var Zend_Validate_Hostname - */ - public $hostnameValidator; - - /** - * Whether we check for a valid MX record via DNS - * - * @var boolean - */ - protected $_validateMx = false; - - /** - * @var string - */ - protected $_hostname; - - /** - * @var string - */ - protected $_localPart; - - /** - * Instantiates hostname validator for local use - * - * You can pass a bitfield to determine what types of hostnames are allowed. - * These bitfields are defined by the ALLOW_* constants in Zend_Validate_Hostname - * The default is to allow DNS hostnames only - * - * @param integer $allow OPTIONAL - * @param bool $validateMx OPTIONAL - * @param Zend_Validate_Hostname $hostnameValidator OPTIONAL - * @return void - */ - public function __construct($allow = Zend_Validate_Hostname::ALLOW_DNS, $validateMx = false, Zend_Validate_Hostname $hostnameValidator = null) - { - $this->setValidateMx($validateMx); - $this->setHostnameValidator($hostnameValidator, $allow); - } - - /** - * @param Zend_Validate_Hostname $hostnameValidator OPTIONAL - * @param int $allow OPTIONAL - * @return void - */ - public function setHostnameValidator(Zend_Validate_Hostname $hostnameValidator = null, $allow = Zend_Validate_Hostname::ALLOW_DNS) - { - if ($hostnameValidator === null) { - $hostnameValidator = new Zend_Validate_Hostname($allow); - } - $this->hostnameValidator = $hostnameValidator; - } - - /** - * Whether MX checking via dns_get_mx is supported or not - * - * This currently only works on UNIX systems - * - * @return boolean - */ - public function validateMxSupported() - { - return function_exists('dns_get_mx'); - } - - /** - * Set whether we check for a valid MX record via DNS - * - * This only applies when DNS hostnames are validated - * - * @param boolean $allowed Set allowed to true to validate for MX records, and false to not validate them - */ - public function setValidateMx($allowed) - { - $this->_validateMx = (bool) $allowed; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is a valid email address - * according to RFC2822 - * - * @link http://www.ietf.org/rfc/rfc2822.txt RFC2822 - * @link http://www.columbia.edu/kermit/ascii.html US-ASCII characters - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - // Split email address up - if (!preg_match('/^(.+)@([^@]+)$/', $valueString, $matches)) { - $this->_error(self::INVALID); - return false; - } - - $this->_localPart = $matches[1]; - $this->_hostname = $matches[2]; - - // Match hostname part - $hostnameResult = $this->hostnameValidator->setTranslator($this->getTranslator()) - ->isValid($this->_hostname); - if (!$hostnameResult) { - $this->_error(self::INVALID_HOSTNAME); - - // Get messages and errors from hostnameValidator - foreach ($this->hostnameValidator->getMessages() as $message) { - $this->_messages[] = $message; - } - foreach ($this->hostnameValidator->getErrors() as $error) { - $this->_errors[] = $error; - } - } - - // MX check on hostname via dns_get_record() - if ($this->_validateMx) { - if ($this->validateMxSupported()) { - $result = dns_get_mx($this->_hostname, $mxHosts); - if (count($mxHosts) < 1) { - $hostnameResult = false; - $this->_error(self::INVALID_MX_RECORD); - } - } else { - /** - * MX checks are not supported by this system - * @see Zend_Validate_Exception - */ - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception('Internal error: MX checking not available on this system'); - } - } - - // First try to match the local part on the common dot-atom format - $localResult = false; - - // Dot-atom characters are: 1*atext *("." 1*atext) - // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*", - // "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~" - $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d'; - if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->_localPart)) { - $localResult = true; - } else { - // Try quoted string format - - // Quoted-string characters are: DQUOTE *([FWS] qtext/quoted-pair) [FWS] DQUOTE - // qtext: Non white space controls, and the rest of the US-ASCII characters not - // including "\" or the quote character - $noWsCtl = '\x01-\x08\x0b\x0c\x0e-\x1f\x7f'; - $qtext = $noWsCtl . '\x21\x23-\x5b\x5d-\x7e'; - $ws = '\x20\x09'; - if (preg_match('/^\x22([' . $ws . $qtext . '])*[$ws]?\x22$/', $this->_localPart)) { - $localResult = true; - } else { - $this->_error(self::DOT_ATOM); - $this->_error(self::QUOTED_STRING); - $this->_error(self::INVALID_LOCAL_PART); - } - } - - // If both parts valid, return true - if ($localResult && $hostnameResult) { - return true; - } else { - return false; - } - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Exception.php b/phpQuery/phpQuery/Zend/Validate/Exception.php deleted file mode 100644 index a38077e..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Exception.php +++ /dev/null @@ -1,37 +0,0 @@ - "Too much files, only '%value%' are allowed", - self::TOO_LESS => "Too less files, minimum '%value%' must be given" - ); - - /** - * @var array Error message template variables - */ - protected $_messageVariables = array( - 'min' => '_min', - 'max' => '_max' - ); - - /** - * Minimum file count - * - * If null, there is no minimum file count - * - * @var integer - */ - protected $_min; - - /** - * Maximum file count - * - * If null, there is no maximum file count - * - * @var integer|null - */ - protected $_max; - - /** - * Internal file array - * @var array - */ - protected $_files; - - /** - * Sets validator options - * - * Min limits the file count, when used with max=null it is the maximum file count - * It also accepts an array with the keys 'min' and 'max' - * - * @param integer|array $min Minimum file count - * @param integer $max Maximum file count - * @return void - */ - public function __construct($min, $max = null) - { - $this->_files = array(); - if (is_array($min) === true) { - if (isset($min['max']) === true) { - $max = $min['max']; - } - - if (isset($min['min']) === true) { - $min = $min['min']; - } - - if (isset($min[0]) === true) { - if (count($min) === 2) { - $max = $min[1]; - $min = $min[0]; - } else { - $max = $min[0]; - $min = null; - } - } - } - - if (empty($max) === true) { - $max = $min; - $min = null; - } - - $this->setMin($min); - $this->setMax($max); - } - - /** - * Returns the minimum file count - * - * @return integer - */ - public function getMin() - { - $min = $this->_min; - - return $min; - } - - /** - * Sets the minimum file count - * - * @param integer $min The minimum file count - * @return Zend_Validate_File_Size Provides a fluent interface - * @throws Zend_Validate_Exception When min is greater than max - */ - public function setMin($min) - { - if ($min === null) { - $this->_min = null; - } else if (($this->_max !== null) and ($min > $this->_max)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception('The minimum must be less than or equal to the maximum file count, but ' - . " {$min} > {$this->_max}"); - } else { - $this->_min = max(0, (integer) $min); - } - - return $this; - } - - /** - * Returns the maximum file count - * - * @return integer|null - */ - public function getMax() - { - return $this->_max; - } - - /** - * Sets the maximum file count - * - * @param integer|null $max The maximum file count - * @throws Zend_Validate_Exception When max is smaller than min - * @return Zend_Validate_StringLength Provides a fluent interface - */ - public function setMax($max) - { - if ($max === null) { - $this->_max = null; - } else if (($this->_min !== null) and ($max < $this->_min)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum file count, but " - . "{$max} < {$this->_min}"); - } else { - $this->_max = (integer) $max; - } - - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the file count of all checked files is at least min and - * not bigger than max (when max is not null). Attention: When checking with set min you - * must give all files with the first call, otherwise you will get an false. - * - * @param string|array $value Filenames to check for count - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - if (is_string($value)) { - $value = array($value); - } - - foreach ($value as $file) { - if (!isset($this->_files[$file])) { - $this->_files[$file] = $file; - } - } - - if (($this->_max !== null) && (count($this->_files) > $this->_max)) { - $this->_value = $this->_max; - $this->_error(self::TOO_MUCH); - return false; - } - - if (($this->_min !== null) && (count($this->_files) < $this->_min)) { - $this->_value = $this->_min; - $this->_error(self::TOO_LESS); - return false; - } - - return true; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/Exists.php b/phpQuery/phpQuery/Zend/Validate/File/Exists.php deleted file mode 100644 index 268090b..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/Exists.php +++ /dev/null @@ -1,192 +0,0 @@ - "The file '%value%' does not exist" - ); - - /** - * Internal list of directories - * @var string - */ - protected $_directory = ''; - - /** - * @var array Error message template variables - */ - protected $_messageVariables = array( - 'directory' => '_directory' - ); - - /** - * Sets validator options - * - * @param string|array $directory - * @return void - */ - public function __construct($directory = array()) - { - $this->setDirectory($directory); - } - - /** - * Returns the set file directories which are checked - * - * @param boolean $asArray Returns the values as array, when false an concated string is returned - * @return string - */ - public function getDirectory($asArray = false) - { - $asArray = (bool) $asArray; - $directory = (string) $this->_directory; - if ($asArray) { - $directory = explode(',', $directory); - } - - return $directory; - } - - /** - * Sets the file directory which will be checked - * - * @param string|array $directory The directories to validate - * @return Zend_Validate_File_Extension Provides a fluent interface - */ - public function setDirectory($directory) - { - $this->_directory = null; - $this->addDirectory($directory); - return $this; - } - - /** - * Adds the file directory which will be checked - * - * @param string|array $directory The directory to add for validation - * @return Zend_Validate_File_Extension Provides a fluent interface - */ - public function addDirectory($directory) - { - $directories = $this->getDirectory(true); - if (is_string($directory)) { - $directory = explode(',', $directory); - } - - foreach ($directory as $content) { - if (empty($content) || !is_string($content)) { - continue; - } - - $directories[] = trim($content); - } - $directories = array_unique($directories); - - // Sanity check to ensure no empty values - foreach ($directories as $key => $dir) { - if (empty($dir)) { - unset($directories[$key]); - } - } - - $this->_directory = implode(',', $directories); - - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the file already exists in the set directories - * - * @param string $value Real file to check for existance - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - $directories = $this->getDirectory(true); - if (($file !== null) and (!empty($file['destination']))) { - $directories[] = $file['destination']; - } else if (!isset($file['name'])) { - $file['name'] = $value; - } - - $check = false; - foreach ($directories as $directory) { - if (empty($directory)) { - continue; - } - - $check = true; - if (!file_exists($directory . DIRECTORY_SEPARATOR . $file['name'])) { - $this->_throw($file, self::DOES_NOT_EXIST); - return false; - } - } - - if (!$check) { - $this->_throw($file, self::DOES_NOT_EXIST); - return false; - } - - return true; - } - - /** - * Throws an error of the given type - * - * @param string $file - * @param string $errorType - * @return false - */ - protected function _throw($file, $errorType) - { - if ($file !== null) { - $this->_value = $file['name']; - } - - $this->_error($errorType); - return false; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/Extension.php b/phpQuery/phpQuery/Zend/Validate/File/Extension.php deleted file mode 100644 index 62577b3..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/Extension.php +++ /dev/null @@ -1,204 +0,0 @@ - "The file '%value%' has a false extension", - self::NOT_FOUND => "The file '%value%' was not found" - ); - - /** - * Internal list of extensions - * @var string - */ - protected $_extension = ''; - - /** - * Validate case sensitive - * - * @var boolean - */ - protected $_case = false; - - /** - * @var array Error message template variables - */ - protected $_messageVariables = array( - 'extension' => '_extension' - ); - - /** - * Sets validator options - * - * @param string|array $extension - * @param boolean $case If true validation is done case sensitive - * @return void - */ - public function __construct($extension, $case = false) - { - $this->_case = (boolean) $case; - $this->setExtension($extension); - } - - /** - * Returns the set file extension - * - * @param boolean $asArray Returns the values as array, when false an concated string is returned - * @return string - */ - public function getExtension($asArray = false) - { - $asArray = (bool) $asArray; - $extension = (string) $this->_extension; - if ($asArray) { - $extension = explode(',', $extension); - } - - return $extension; - } - - /** - * Sets the file extensions - * - * @param string|array $extension The extensions to validate - * @return Zend_Validate_File_Extension Provides a fluent interface - */ - public function setExtension($extension) - { - $this->_extension = null; - $this->addExtension($extension); - return $this; - } - - /** - * Adds the file extensions - * - * @param string|array $extension The extensions to add for validation - * @return Zend_Validate_File_Extension Provides a fluent interface - */ - public function addExtension($extension) - { - $extensions = $this->getExtension(true); - if (is_string($extension)) { - $extension = explode(',', $extension); - } - - foreach ($extension as $content) { - if (empty($content) || !is_string($content)) { - continue; - } - - $extensions[] = trim($content); - } - $extensions = array_unique($extensions); - - // Sanity check to ensure no empty values - foreach ($extensions as $key => $ext) { - if (empty($ext)) { - unset($extensions[$key]); - } - } - - $this->_extension = implode(',', $extensions); - - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the fileextension of $value is included in the - * set extension list - * - * @param string $value Real file to check for extension - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - // Is file readable ? - if (!@is_readable($value)) { - $this->_throw($file, self::NOT_FOUND); - return false; - } - - if ($file !== null) { - $info['extension'] = substr($file['name'], strpos($file['name'], '.') + 1); - } else { - $info = @pathinfo($value); - } - - $extensions = $this->getExtension(true); - - if ($this->_case and (in_array($info['extension'], $extensions))) { - return true; - } else if (!$this->_case) { - foreach ($extensions as $extension) { - if (strtolower($extension) == strtolower($info['extension'])) { - return true; - } - } - } - - $this->_throw($file, self::FALSE_EXTENSION); - return false; - } - - /** - * Throws an error of the given type - * - * @param string $file - * @param string $errorType - * @return false - */ - protected function _throw($file, $errorType) - { - if ($file !== null) { - $this->_value = $file['name']; - } - - $this->_error($errorType); - return false; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/FilesSize.php b/phpQuery/phpQuery/Zend/Validate/File/FilesSize.php deleted file mode 100644 index e8b060d..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/FilesSize.php +++ /dev/null @@ -1,156 +0,0 @@ - "The files in sum exceed the maximum allowed size", - self::TOO_SMALL => "All files are in sum smaller than required", - self::NOT_READABLE => "One or more files can not be read" - ); - - /** - * @var array Error message template variables - */ - protected $_messageVariables = array( - 'min' => '_min', - 'max' => '_max' - ); - - /** - * Minimum filesize - * - * @var integer - */ - protected $_min; - - /** - * Maximum filesize - * - * @var integer|null - */ - protected $_max; - - /** - * Internal file array - * - * @var array - */ - protected $_files; - - /** - * Internal file size counter - * - * @var integer - */ - protected $_size; - - /** - * Sets validator options - * - * Min limits the used diskspace for all files, when used with max=null it is the maximum filesize - * It also accepts an array with the keys 'min' and 'max' - * - * @param integer|array $min Minimum diskspace for all files - * @param integer $max Maximum diskspace for all files - * @return void - */ - public function __construct($min, $max = null) - { - $this->_files = array(); - $this->_size = 0; - parent::__construct($min, $max); - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the disk usage of all files is at least min and - * not bigger than max (when max is not null). - * - * @param string|array $value Real file to check for size - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - if (is_string($value)) { - $value = array($value); - } - - foreach ($value as $files) { - // Is file readable ? - if (!@is_readable($files)) { - $this->_throw($file, self::NOT_READABLE); - return false; - } - - if (!isset($this->_files[$files])) { - $this->_files[$files] = $files; - } else { - // file already counted... do not count twice - continue; - } - - // limited to 2GB files - $size = @filesize($files); - $this->_size += $size; - $this->_setValue($this->_size); - if (($this->_max !== null) && ($this->_max < $this->_size)) { - $this->_throw($file, self::TOO_BIG); - } - } - - // Check that aggregate files are >= minimum size - if (($this->_min !== null) && ($this->_size < $this->_min)) { - $this->_throw($file, self::TOO_SMALL); - } - - if (count($this->_messages) > 0) { - return false; - } else { - return true; - } - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/ImageSize.php b/phpQuery/phpQuery/Zend/Validate/File/ImageSize.php deleted file mode 100644 index 6c27ef6..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/ImageSize.php +++ /dev/null @@ -1,335 +0,0 @@ - "Width of the image '%value%' is bigger than allowed", - self::WIDTH_TOO_SMALL => "Width of the image '%value%' is smaller than allowed", - self::HEIGHT_TOO_BIG => "Height of the image '%value%' is bigger than allowed", - self::HEIGHT_TOO_SMALL => "Height of the image '%value%' is smaller than allowed", - self::NOT_DETECTED => "Size of the image '%value%' could not be detected", - self::NOT_READABLE => "The image '%value%' can not be read" - ); - - /** - * @var array Error message template variables - */ - protected $_messageVariables = array( - 'minwidth' => '_minwidth', - 'maxwidth' => '_maxwidth', - 'minheight' => '_minheight', - 'maxheight' => '_maxheight' - ); - - /** - * Minimum image width - * - * @var integer - */ - protected $_minwidth; - - /** - * Maximum image width - * - * @var integer - */ - protected $_maxwidth; - - /** - * Minimum image height - * - * @var integer - */ - protected $_minheight; - - /** - * Maximum image height - * - * @var integer - */ - protected $_maxheight; - - /** - * Sets validator options - * - * Min limits the filesize, when used with max=null if is the maximum filesize - * It also accepts an array with the keys 'min' and 'max' - * - * @param integer|array $max Maximum filesize - * @param integer $max Maximum filesize - * @return void - */ - public function __construct($minwidth = 0, $minheight = 0, $maxwidth = null, $maxheight = null) - { - if (is_array($minwidth) === true) { - if (isset($minwidth['maxheight']) === true) { - $maxheight = $minwidth['maxheight']; - } - - if (isset($minwidth['minheight']) === true) { - $minheight = $minwidth['minheight']; - } - - if (isset($minwidth['maxwidth']) === true) { - $maxwidth = $minwidth['maxwidth']; - } - - if (isset($minwidth['minwidth']) === true) { - $minwidth = $minwidth['minwidth']; - } - - if (isset($minwidth[0]) === true) { - $maxheight = $minwidth[3]; - $maxwidth = $minwidth[2]; - $minheight = $minwidth[1]; - $minwidth = $minwidth[0]; - } - } - - $this->setImageMin($minwidth, $minheight); - $this->setImageMax($maxwidth, $maxheight); - } - - /** - * Returns the set minimum image sizes - * - * @return array - */ - public function getImageMin() - { - return array($this->_minwidth, $this->_minheight); - } - - /** - * Returns the set maximum image sizes - * - * @return array - */ - public function getImageMax() - { - return array($this->_maxwidth, $this->_maxheight); - } - - /** - * Returns the set image width sizes - * - * @return array - */ - public function getImageWidth() - { - return array($this->_minwidth, $this->_maxwidth); - } - - /** - * Returns the set image height sizes - * - * @return array - */ - public function getImageHeight() - { - return array($this->_minheight, $this->_maxheight); - } - - /** - * Sets the minimum image size - * - * @param integer $minwidth The minimum image width - * @param integer $minheight The minimum image height - * @throws Zend_Validate_Exception When minwidth is greater than maxwidth - * @throws Zend_Validate_Exception When minheight is greater than maxheight - * @return Zend_Validate_File_ImageSize Provides a fluent interface - */ - public function setImageMin($minwidth, $minheight) - { - if (($this->_maxwidth !== null) and ($minwidth > $this->_maxwidth)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The minimum image width must be less than or equal to the " - . " maximum image width, but {$minwidth} > {$this->_maxwidth}"); - } - - if (($this->_maxheight !== null) and ($minheight > $this->_maxheight)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The minimum image height must be less than or equal to the " - . " maximum image height, but {$minheight} > {$this->_maxheight}"); - } - - $this->_minwidth = max(0, (integer) $minwidth); - $this->_minheight = max(0, (integer) $minheight); - return $this; - } - - /** - * Sets the maximum image size - * - * @param integer $maxwidth The maximum image width - * @param integer $maxheight The maximum image height - * @throws Zend_Validate_Exception When maxwidth is smaller than minwidth - * @throws Zend_Validate_Exception When maxheight is smaller than minheight - * @return Zend_Validate_StringLength Provides a fluent interface - */ - public function setImageMax($maxwidth, $maxheight) - { - if ($maxwidth === null) { - $tempwidth = null; - } else if (($this->_minwidth !== null) and ($maxwidth < $this->_minwidth)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The maximum image width must be greater than or equal to the " - . "minimum image width, but {$maxwidth} < {$this->_minwidth}"); - } else { - $tempwidth = (integer) $maxwidth; - } - - if ($maxheight === null) { - $tempheight = null; - } else if (($this->_minheight !== null) and ($maxheight < $this->_minheight)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The maximum image height must be greater than or equal to the " - . "minimum image height, but {$maxheight} < {$this->_minwidth}"); - } else { - $tempheight = (integer) $maxheight; - } - - $this->_maxwidth = $tempwidth; - $this->_maxheight = $tempheight; - return $this; - } - - /** - * Sets the mimimum and maximum image width - * - * @param integer $minwidth The minimum image width - * @param integer $maxwidth The maximum image width - * @return Zend_Validate_File_ImageSize Provides a fluent interface - */ - public function setImageWidth($minwidth, $maxwidth) - { - $this->setImageMin($minwidth, $this->_minheight); - $this->setImageMax($maxwidth, $this->_maxheight); - return $this; - } - - /** - * Sets the mimimum and maximum image height - * - * @param integer $minheight The minimum image height - * @param integer $maxheight The maximum image height - * @return Zend_Validate_File_ImageSize Provides a fluent interface - */ - public function setImageHeight($minheight, $maxheight) - { - $this->setImageMin($this->_minwidth, $minheight); - $this->setImageMax($this->_maxwidth, $maxheight); - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the imagesize of $value is at least min and - * not bigger than max - * - * @param string $value Real file to check for image size - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - // Is file readable ? - if (@is_readable($value) === false) { - $this->_throw($file, self::NOT_READABLE); - return false; - } - - $size = @getimagesize($value); - $this->_setValue($file); - - if (empty($size) or ($size[0] === 0) or ($size[1] === 0)) { - $this->_throw($file, self::NOT_DETECTED); - return false; - } - - if ($size[0] < $this->_minwidth) { - $this->_throw($file, self::WIDTH_TOO_SMALL); - } - - if ($size[1] < $this->_minheight) { - $this->_throw($file, self::HEIGHT_TOO_SMALL); - } - - if (($this->_maxwidth !== null) and ($this->_maxwidth < $size[0])) { - $this->_throw($file, self::WIDTH_TOO_BIG); - } - - if (($this->_maxheight !== null) and ($this->_maxheight < $size[1])) { - $this->_throw($file, self::HEIGHT_TOO_BIG); - } - - if (count($this->_messages) > 0) { - return false; - } else { - return true; - } - } - - /** - * Throws an error of the given type - * - * @param string $file - * @param string $errorType - * @return false - */ - protected function _throw($file, $errorType) - { - if ($file !== null) { - $this->_value = $file['name']; - } - - $this->_error($errorType); - return false; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/MimeType.php b/phpQuery/phpQuery/Zend/Validate/File/MimeType.php deleted file mode 100644 index 8f7e9cd..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/MimeType.php +++ /dev/null @@ -1,200 +0,0 @@ - "The file '%value%' has a false mimetype", - self::NOT_DETECTED => "The mimetype of file '%value%' has not been detected", - self::NOT_READABLE => "The file '%value%' can not be read" - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'mimetype' => '_mimetype' - ); - - /** - * Mimetypes - * - * If null, there is no mimetype - * - * @var string|null - */ - protected $_mimetype; - - /** - * Sets validator options - * - * Mimetype to accept - * - * @param string|array $mimetype MimeType - * @return void - */ - public function __construct($mimetype) - { - $this->setMimeType($mimetype); - } - - /** - * Returns the set mimetypes - * - * @param boolean $asArray Returns the values as array, when false an concated string is returned - * @return integer - */ - public function getMimeType($asArray = false) - { - $asArray = (bool) $asArray; - $mimetype = (string) $this->_mimetype; - if ($asArray) { - $mimetype = explode(',', $mimetype); - } - - return $mimetype; - } - - /** - * Sets the mimetypes - * - * @param string|array $mimetype The mimetypes to validate - * @return Zend_Validate_File_Extension Provides a fluent interface - */ - public function setMimeType($mimetype) - { - $this->_mimetype = null; - $this->addMimeType($mimetype); - return $this; - } - - /** - * Adds the mimetypes - * - * @param string|array $mimetype The mimetypes to add for validation - * @return Zend_Validate_File_Extension Provides a fluent interface - */ - public function addMimeType($mimetype) - { - $mimetypes = $this->getMimeType(true); - if (is_string($mimetype)) { - $mimetype = explode(',', $mimetype); - } - - foreach ($mimetype as $content) { - if (empty($content) || !is_string($content)) { - continue; - } - $mimetypes[] = trim($content); - } - $mimetypes = array_unique($mimetypes); - - // Sanity check to ensure no empty values - foreach ($mimetypes as $key => $mt) { - if (empty($mt)) { - unset($mimetypes[$key]); - } - } - - $this->_mimetype = implode(',', $mimetypes); - - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if the mimetype of the file matches the given ones. Also parts - * of mimetypes can be checked. If you give for example "image" all image - * mime types will be accepted like "image/gif", "image/jpeg" and so on. - * - * @param string $value Real file to check for mimetype - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - // Is file readable ? - if (!@is_readable($value)) { - $this->_throw($file, self::NOT_READABLE); - return false; - } - - if ($file !== null) { - $info['type'] = $file['type']; - } else { - $this->_throw($file, self::NOT_DETECTED); - return false; - } - - $mimetype = $this->getMimeType(true); - if (in_array($info['type'], $mimetype)) { - return true; - } - - foreach($mimetype as $mime) { - $types = explode('/', $info['type']); - if (in_array($mime, $types)) { - return true; - } - } - - $this->_throw($file, self::FALSE_TYPE); - return false; - } - - /** - * Throws an error of the given type - * - * @param string $file - * @param string $errorType - * @return false - */ - protected function _throw($file, $errorType) - { - if ($file !== null) { - $this->_value = $file['name']; - } - - $this->_error($errorType); - return false; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/NotExists.php b/phpQuery/phpQuery/Zend/Validate/File/NotExists.php deleted file mode 100644 index 2b812fc..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/NotExists.php +++ /dev/null @@ -1,86 +0,0 @@ - "The file '%value%' does exist" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the file does not exist in the set destinations - * - * @param string $value Real file to check for - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - $directories = $this->getDirectory(true); - if (($file !== null) and (!empty($file['destination']))) { - $directories[] = $file['destination']; - } else if (!isset($file['name'])) { - $file['name'] = $value; - } - - foreach ($directories as $directory) { - if (empty($directory)) { - continue; - } - - $check = true; - if (file_exists($directory . DIRECTORY_SEPARATOR . $file['name'])) { - $this->_throw($file, self::DOES_EXIST); - return false; - } - } - - if (!isset($check)) { - $this->_throw($file, self::DOES_EXIST); - return false; - } - - return true; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/Size.php b/phpQuery/phpQuery/Zend/Validate/File/Size.php deleted file mode 100644 index 2adaeb3..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/Size.php +++ /dev/null @@ -1,308 +0,0 @@ - "The file '%value%' is bigger than allowed", - self::TOO_SMALL => "The file '%value%' is smaller than allowed", - self::NOT_FOUND => "The file '%value%' could not be found" - ); - - /** - * @var array Error message template variables - */ - protected $_messageVariables = array( - 'min' => '_min', - 'max' => '_max' - ); - - /** - * Minimum filesize - * @var integer - */ - protected $_min; - - /** - * Maximum filesize - * - * If null, there is no maximum filesize - * - * @var integer|null - */ - protected $_max; - - /** - * Sets validator options - * - * Min limits the filesize, when used with max=null it is the maximum filesize - * It also accepts an array with the keys 'min' and 'max' - * - * @param integer|array $min Minimum filesize - * @param integer $max Maximum filesize - * @return void - */ - public function __construct($min, $max = null) - { - if (is_array($min)) { - $count = count($min); - if (array_key_exists('min', $min)) { - if (array_key_exists('max', $min)) { - $max = $min['max']; - } - - $min = $min['min']; - } elseif ($count === 2) { - $minValue = array_shift($min); - $max = array_shift($min); - $min = $minValue; - } elseif($count === 1) { - $min = array_shift($min); - $max = null; - } else { - $min = 0; - $max = null; - } - } - - if (empty($max)) { - $max = $min; - $min = 0; - } - - $this->setMin($min); - $this->setMax($max); - } - - /** - * Returns the minimum filesize - * - * @param boolean $unit Return the value with unit, when false the plan bytes will be returned - * @return integer - */ - public function getMin($unit = true) - { - $unit = (bool) $unit; - $min = $this->_min; - if ($unit) { - $min = $this->_toByteString($min); - } - return $min; - } - - /** - * Sets the minimum filesize - * - * @param integer $min The minimum filesize - * @return Zend_Validate_File_Size Provides a fluent interface - * @throws Zend_Validate_Exception When min is greater than max - */ - public function setMin($min) - { - $min = (integer) $this->_fromByteString($min); - if (($this->_max !== null) && ($min > $this->_max)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum filesize, but $min >" - . " {$this->_max}"); - } - - $this->_min = max(0, $min); - return $this; - } - - /** - * Returns the maximum filesize - * - * @param boolean $unit Return the value with unit, when false the plan bytes will be returned - * @return integer|null - */ - public function getMax($unit = true) - { - $unit = (bool) $unit; - $max = $this->_max; - if ($unit) { - $max = $this->_toByteString($max); - } - return $max; - } - - /** - * Sets the maximum filesize - * - * @param integer|null $max The maximum filesize - * @return Zend_Validate_StringLength Provides a fluent interface - * @throws Zend_Validate_Exception When max is smaller than min - */ - public function setMax($max) - { - $max = (integer) $this->_fromByteString($max); - if (($this->_min !== null) && ($max < $this->_min)) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum filesize, but " - . "$max < {$this->_min}"); - } else { - $this->_max = $max; - } - - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the filesize of $value is at least min and - * not bigger than max (when max is not null). - * - * @param string $value Real file to check for size - * @param array $file File data from Zend_File_Transfer - * @return boolean - */ - public function isValid($value, $file = null) - { - // Is file readable ? - if (!@is_readable($value)) { - $this->_throw($file, self::NOT_FOUND); - return false; - } - - // limited to 4GB files - $size = sprintf("%u",@filesize($value)); - $this->_setValue($size); - - // Check to see if it's smaller than min size - if (($this->_min !== null) && ($size < $this->_min)) { - $this->_throw($file, self::TOO_SMALL); - } - - // Check to see if it's larger than max size - if (($this->_max !== null) && ($this->_max < $size)) { - $this->_throw($file, self::TOO_BIG); - } - - if (count($this->_messages) > 0) { - return false; - } else { - return true; - } - } - - /** - * Returns the formatted size - * - * @param integer $size - * @return string - */ - protected function _toByteString($size) - { - $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); - for ($i=0; $size > 1024 && $i < 9; $i++) { - $size /= 1024; - } - return round($size, 2).$sizes[$i]; - } - - /** - * Returns the unformatted size - * - * @param string $size - * @return integer - */ - protected function _fromByteString($size) - { - if (is_numeric($size)) { - return (integer) $size; - } - - $type = trim(substr($size, -2)); - $value = substr($size, 0, -2); - switch (strtoupper($type)) { - case 'YB': - $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024); - break; - case 'ZB': - $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024); - break; - case 'EB': - $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024); - break; - case 'PB': - $value *= (1024 * 1024 * 1024 * 1024 * 1024); - break; - case 'TB': - $value *= (1024 * 1024 * 1024 * 1024); - break; - case 'GB': - $value *= (1024 * 1024 * 1024); - break; - case 'MB': - $value *= (1024 * 1024); - break; - case 'KB': - $value *= 1024; - break; - default: - break; - } - - return $value; - } - - /** - * Throws an error of the given type - * - * @param string $file - * @param string $errorType - * @return false - */ - protected function _throw($file, $errorType) - { - if ($file !== null) { - $this->_value = $file['name']; - } - - $this->_error($errorType); - return false; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/File/Upload.php b/phpQuery/phpQuery/Zend/Validate/File/Upload.php deleted file mode 100644 index a56cf14..0000000 --- a/phpQuery/phpQuery/Zend/Validate/File/Upload.php +++ /dev/null @@ -1,216 +0,0 @@ - "The file '%value%' exceeds the defined ini size", - self::FORM_SIZE => "The file '%value%' exceeds the defined form size", - self::PARTIAL => "The file '%value%' was only partially uploaded", - self::NO_FILE => "The file '%value%' was not uploaded", - self::NO_TMP_DIR => "No temporary directory was found for the file '%value%'", - self::CANT_WRITE => "The file '%value%' can't be written", - self::EXTENSION => "The extension returned an error while uploading the file '%value%'", - self::ATTACK => "The file '%value%' was illegal uploaded, possible attack", - self::FILE_NOT_FOUND => "The file '%value%' was not found", - self::UNKNOWN => "Unknown error while uploading the file '%value%'" - ); - - /** - * Internal array of files - * @var array - */ - protected $_files = array(); - - /** - * Sets validator options - * - * The array $files must be given in syntax of Zend_File_Transfer to be checked - * If no files are given the $_FILES array will be used automatically. - * NOTE: This validator will only work with HTTP POST uploads! - * - * @param array $files Array of files in syntax of Zend_File_Transfer - * @return void - */ - public function __construct($files = array()) - { - $this->setFiles($files); - } - - /** - * Returns the array of set files - * - * @param string $files (Optional) The file to return in detail - * @return array - * @throws Zend_Validate_Exception If file is not found - */ - public function getFiles($file = null) - { - if ($file !== null) { - $return = array(); - foreach ($this->_files as $name => $content) { - if ($name === $file) { - $return[$file] = $this->_files[$name]; - } - - if ($content['name'] === $file) { - $return[$name] = $this->_files[$name]; - } - } - - if (count($return) === 0) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The file '$file' was not found"); - } - - return $return; - } - - return $this->_files; - } - - /** - * Sets the minimum filesize - * - * @param array $files The files to check in syntax of Zend_File_Transfer - * @return Zend_Validate_File_Upload Provides a fluent interface - */ - public function setFiles($files = array()) - { - if (count($files) === 0) { - $this->_files = $_FILES; - } else { - $this->_files = $files; - } - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the file was uploaded without errors - * - * @param string $value Single file to check for upload errors, when giving null the $_FILES array - * from initialization will be used - * @return boolean - */ - public function isValid($value) - { - if (array_key_exists($value, $this->_files)) { - $files[$value] = $this->_files[$value]; - } else { - foreach ($this->_files as $file => $content) { - if ($content['name'] === $value) { - $files[$file] = $this->_files[$file]; - } - - if ($content['tmp_name'] === $value) { - $files[$file] = $this->_files[$file]; - } - } - } - - if (empty($files)) { - $this->_error(self::FILE_NOT_FOUND); - return false; - } - - foreach ($files as $file => $content) { - $this->_value = $file; - switch($content['error']) { - case 0: - if (!is_uploaded_file($content['tmp_name'])) { - $this->_error(self::ATTACK); - } - break; - - case 1: - $this->_error(self::INI_SIZE); - break; - - case 2: - $this->_error(self::FORM_SIZE); - break; - - case 3: - $this->_error(self::PARTIAL); - break; - - case 4: - $this->_error(self::NO_FILE); - break; - - case 6: - $this->_error(self::NO_TMP_DIR); - break; - - case 7: - $this->_error(self::CANT_WRITE); - break; - - case 8: - $this->_error(self::EXTENSION); - break; - - default: - $this->_error(self::UNKNOWN); - break; - } - } - - if (count($this->_messages) > 0) { - return false; - } else { - return true; - } - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/Float.php b/phpQuery/phpQuery/Zend/Validate/Float.php deleted file mode 100644 index 0405161..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Float.php +++ /dev/null @@ -1,75 +0,0 @@ - "'%value%' does not appear to be a float" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is a floating-point value - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - $locale = localeconv(); - - $valueFiltered = str_replace($locale['thousands_sep'], '', $valueString); - $valueFiltered = str_replace($locale['decimal_point'], '.', $valueFiltered); - - if (strval(floatval($valueFiltered)) != $valueFiltered) { - $this->_error(); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/GreaterThan.php b/phpQuery/phpQuery/Zend/Validate/GreaterThan.php deleted file mode 100644 index 35e658c..0000000 --- a/phpQuery/phpQuery/Zend/Validate/GreaterThan.php +++ /dev/null @@ -1,114 +0,0 @@ - "'%value%' is not greater than '%min%'" - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'min' => '_min' - ); - - /** - * Minimum value - * - * @var mixed - */ - protected $_min; - - /** - * Sets validator options - * - * @param mixed $min - * @return void - */ - public function __construct($min) - { - $this->setMin($min); - } - - /** - * Returns the min option - * - * @return mixed - */ - public function getMin() - { - return $this->_min; - } - - /** - * Sets the min option - * - * @param mixed $min - * @return Zend_Validate_GreaterThan Provides a fluent interface - */ - public function setMin($min) - { - $this->_min = $min; - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is greater than min option - * - * @param mixed $value - * @return boolean - */ - public function isValid($value) - { - $this->_setValue($value); - - if ($this->_min >= $value) { - $this->_error(); - return false; - } - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Hex.php b/phpQuery/phpQuery/Zend/Validate/Hex.php deleted file mode 100644 index 9512eda..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Hex.php +++ /dev/null @@ -1,74 +0,0 @@ - "'%value%' has not only hexadecimal digit characters" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value contains only hexadecimal digit characters - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - if (!ctype_xdigit($valueString)) { - $this->_error(); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Hostname.php b/phpQuery/phpQuery/Zend/Validate/Hostname.php deleted file mode 100644 index ea79c24..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Hostname.php +++ /dev/null @@ -1,444 +0,0 @@ - "'%value%' appears to be an IP address, but IP addresses are not allowed", - self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list", - self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash (-) in an invalid position", - self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'", - self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part", - self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname", - self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name", - self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed" - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'tld' => '_tld' - ); - - /** - * Allows Internet domain names (e.g., example.com) - */ - const ALLOW_DNS = 1; - - /** - * Allows IP addresses - */ - const ALLOW_IP = 2; - - /** - * Allows local network names (e.g., localhost, www.localdomain) - */ - const ALLOW_LOCAL = 4; - - /** - * Allows all types of hostnames - */ - const ALLOW_ALL = 7; - - /** - * Whether IDN domains are validated - * - * @var boolean - */ - private $_validateIdn = true; - - /** - * Whether TLDs are validated against a known list - * - * @var boolean - */ - private $_validateTld = true; - - /** - * Bit field of ALLOW constants; determines which types of hostnames are allowed - * - * @var integer - */ - protected $_allow; - - /** - * Bit field of CHECK constants; determines what additional hostname checks to make - * - * @var unknown_type - */ - // protected $_check; - - /** - * Array of valid top-level-domains - * - * @var array - * @see ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain - */ - protected $_validTlds = array( - 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', - 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', - 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bm', 'bn', 'bo', - 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', - 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', - 'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', - 'dz', 'ec', 'edu', 'ee', 'eg', 'er', 'es', 'et', 'eu', 'fi', 'fj', - 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', - 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', - 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', - 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', - 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', - 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', - 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', - 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', - 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', - 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', - 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', - 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', - 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', - 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', - 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', - 'tz', 'ua', 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', - 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', - 'zw' - ); - - /** - * @var string - */ - protected $_tld; - - /** - * Sets validator options - * - * @param integer $allow OPTIONAL Set what types of hostname to allow (default ALLOW_DNS) - * @param boolean $validateIdn OPTIONAL Set whether IDN domains are validated (default true) - * @param boolean $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true) - * @param Zend_Validate_Ip $ipValidator OPTIONAL - * @return void - * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm Technical Specifications for ccTLDs - */ - public function __construct($allow = self::ALLOW_DNS, $validateIdn = true, $validateTld = true, Zend_Validate_Ip $ipValidator = null) - { - // Set allow options - $this->setAllow($allow); - - // Set validation options - $this->_validateIdn = $validateIdn; - $this->_validateTld = $validateTld; - - $this->setIpValidator($ipValidator); - } - - /** - * @param Zend_Validate_Ip $ipValidator OPTIONAL - * @return void; - */ - public function setIpValidator(Zend_Validate_Ip $ipValidator = null) - { - if ($ipValidator === null) { - $ipValidator = new Zend_Validate_Ip(); - } - $this->_ipValidator = $ipValidator; - } - - /** - * Returns the allow option - * - * @return integer - */ - public function getAllow() - { - return $this->_allow; - } - - /** - * Sets the allow option - * - * @param integer $allow - * @return Zend_Validate_Hostname Provides a fluent interface - */ - public function setAllow($allow) - { - $this->_allow = $allow; - return $this; - } - - /** - * Set whether IDN domains are validated - * - * This only applies when DNS hostnames are validated - * - * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them - */ - public function setValidateIdn ($allowed) - { - $this->_validateIdn = (bool) $allowed; - } - - /** - * Set whether the TLD element of a hostname is validated - * - * This only applies when DNS hostnames are validated - * - * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them - */ - public function setValidateTld ($allowed) - { - $this->_validateTld = (bool) $allowed; - } - - /** - * Sets the check option - * - * @param integer $check - * @return Zend_Validate_Hostname Provides a fluent interface - */ - /* - public function setCheck($check) - { - $this->_check = $check; - return $this; - } - */ - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the $value is a valid hostname with respect to the current allow option - * - * @param string $value - * @throws Zend_Validate_Exception if a fatal error occurs for validation process - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - // Check input against IP address schema - if ($this->_ipValidator->setTranslator($this->getTranslator())->isValid($valueString)) { - if (!($this->_allow & self::ALLOW_IP)) { - $this->_error(self::IP_ADDRESS_NOT_ALLOWED); - return false; - } else{ - return true; - } - } - - // Check input against DNS hostname schema - $domainParts = explode('.', $valueString); - if ((count($domainParts) > 1) && (strlen($valueString) >= 4) && (strlen($valueString) <= 254)) { - $status = false; - - do { - // First check TLD - if (preg_match('/([a-z]{2,10})$/i', end($domainParts), $matches)) { - - reset($domainParts); - - // Hostname characters are: *(label dot)(label dot label); max 254 chars - // label: id-prefix [*ldh{61} id-prefix]; max 63 chars - // id-prefix: alpha / digit - // ldh: alpha / digit / dash - - // Match TLD against known list - $this->_tld = strtolower($matches[1]); - if ($this->_validateTld) { - if (!in_array($this->_tld, $this->_validTlds)) { - $this->_error(self::UNKNOWN_TLD); - $status = false; - break; - } - } - - /** - * Match against IDN hostnames - * @see Zend_Validate_Hostname_Interface - */ - $labelChars = 'a-z0-9'; - $utf8 = false; - $classFile = 'Zend/Validate/Hostname/' . ucfirst($this->_tld) . '.php'; - if ($this->_validateIdn) { - if (Zend_Loader::isReadable($classFile)) { - - // Load additional characters - $className = 'Zend_Validate_Hostname_' . ucfirst($this->_tld); - Zend_Loader::loadClass($className); - $labelChars .= call_user_func(array($className, 'getCharacters')); - $utf8 = true; - } - } - - // Keep label regex short to avoid issues with long patterns when matching IDN hostnames - $regexLabel = '/^[' . $labelChars . '\x2d]{1,63}$/i'; - if ($utf8) { - $regexLabel .= 'u'; - } - - // Check each hostname part - $valid = true; - foreach ($domainParts as $domainPart) { - - // Check dash (-) does not start, end or appear in 3rd and 4th positions - if (strpos($domainPart, '-') === 0 || - (strlen($domainPart) > 2 && strpos($domainPart, '-', 2) == 2 && strpos($domainPart, '-', 3) == 3) || - strrpos($domainPart, '-') === strlen($domainPart) - 1) { - - $this->_error(self::INVALID_DASH); - $status = false; - break 2; - } - - // Check each domain part - $status = @preg_match($regexLabel, $domainPart); - if ($status === false) { - /** - * Regex error - * @see Zend_Validate_Exception - */ - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception('Internal error: DNS validation failed'); - } elseif ($status === 0) { - $valid = false; - } - } - - // If all labels didn't match, the hostname is invalid - if (!$valid) { - $this->_error(self::INVALID_HOSTNAME_SCHEMA); - $status = false; - } - - } else { - // Hostname not long enough - $this->_error(self::UNDECIPHERABLE_TLD); - $status = false; - } - } while (false); - - // If the input passes as an Internet domain name, and domain names are allowed, then the hostname - // passes validation - if ($status && ($this->_allow & self::ALLOW_DNS)) { - return true; - } - } else { - $this->_error(self::INVALID_HOSTNAME); - } - - // Check input against local network name schema; last chance to pass validation - $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}){1,254}$/'; - $status = @preg_match($regexLocal, $valueString); - if (false === $status) { - /** - * Regex error - * @see Zend_Validate_Exception - */ - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception('Internal error: local network name validation failed'); - } - - // If the input passes as a local network name, and local network names are allowed, then the - // hostname passes validation - $allowLocal = $this->_allow & self::ALLOW_LOCAL; - if ($status && $allowLocal) { - return true; - } - - // If the input does not pass as a local network name, add a message - if (!$status) { - $this->_error(self::INVALID_LOCAL_NAME); - } - - // If local network names are not allowed, add a message - if ($status && !$allowLocal) { - $this->_error(self::LOCAL_NAME_NOT_ALLOWED); - } - - return false; - } - - /** - * Throws an exception if a regex for $type does not exist - * - * @param string $type - * @throws Zend_Validate_Exception - * @return Zend_Validate_Hostname Provides a fluent interface - */ - /* - protected function _checkRegexType($type) - { - if (!isset($this->_regex[$type])) { - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("'$type' must be one of ('" . implode(', ', array_keys($this->_regex)) - . "')"); - } - return $this; - } - */ - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Hostname/At.php b/phpQuery/phpQuery/Zend/Validate/Hostname/At.php deleted file mode 100644 index fff6bf2..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Hostname/At.php +++ /dev/null @@ -1,50 +0,0 @@ - 'Tokens do not match', - self::MISSING_TOKEN => 'No token was provided to match against', - ); - - /** - * Original token against which to validate - * @var string - */ - protected $_token; - - /** - * Sets validator options - * - * @param string $token - * @return void - */ - public function __construct($token = null) - { - if (null !== $token) { - $this->setToken($token); - } - } - - /** - * Set token against which to compare - * - * @param string $token - * @return Zend_Validate_Identical - */ - public function setToken($token) - { - $this->_token = (string) $token; - return $this; - } - - /** - * Retrieve token - * - * @return string - */ - public function getToken() - { - return $this->_token; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if a token has been set and the provided value - * matches that token. - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $this->_setValue($value); - $token = $this->getToken(); - - if (empty($token)) { - $this->_error(self::MISSING_TOKEN); - return false; - } - - if ($value !== $token) { - $this->_error(self::NOT_SAME); - return false; - } - - return true; - } -} diff --git a/phpQuery/phpQuery/Zend/Validate/InArray.php b/phpQuery/phpQuery/Zend/Validate/InArray.php deleted file mode 100644 index 1c7725a..0000000 --- a/phpQuery/phpQuery/Zend/Validate/InArray.php +++ /dev/null @@ -1,138 +0,0 @@ - "'%value%' was not found in the haystack" - ); - - /** - * Haystack of possible values - * - * @var array - */ - protected $_haystack; - - /** - * Whether a strict in_array() invocation is used - * - * @var boolean - */ - protected $_strict; - - /** - * Sets validator options - * - * @param array $haystack - * @param boolean $strict - * @return void - */ - public function __construct(array $haystack, $strict = false) - { - $this->setHaystack($haystack) - ->setStrict($strict); - } - - /** - * Returns the haystack option - * - * @return mixed - */ - public function getHaystack() - { - return $this->_haystack; - } - - /** - * Sets the haystack option - * - * @param mixed $haystack - * @return Zend_Validate_InArray Provides a fluent interface - */ - public function setHaystack(array $haystack) - { - $this->_haystack = $haystack; - return $this; - } - - /** - * Returns the strict option - * - * @return boolean - */ - public function getStrict() - { - return $this->_strict; - } - - /** - * Sets the strict option - * - * @param boolean $strict - * @return Zend_Validate_InArray Provides a fluent interface - */ - public function setStrict($strict) - { - $this->_strict = $strict; - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is contained in the haystack option. If the strict - * option is true, then the type of $value is also checked. - * - * @param mixed $value - * @return boolean - */ - public function isValid($value) - { - $this->_setValue($value); - if (!in_array($value, $this->_haystack, $this->_strict)) { - $this->_error(); - return false; - } - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Int.php b/phpQuery/phpQuery/Zend/Validate/Int.php deleted file mode 100644 index 0bde2cb..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Int.php +++ /dev/null @@ -1,75 +0,0 @@ - "'%value%' does not appear to be an integer" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is a valid integer - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - $locale = localeconv(); - - $valueFiltered = str_replace($locale['decimal_point'], '.', $valueString); - $valueFiltered = str_replace($locale['thousands_sep'], '', $valueFiltered); - - if (strval(intval($valueFiltered)) != $valueFiltered) { - $this->_error(); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Interface.php b/phpQuery/phpQuery/Zend/Validate/Interface.php deleted file mode 100644 index 4fcd525..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Interface.php +++ /dev/null @@ -1,71 +0,0 @@ - "'%value%' does not appear to be a valid IP address" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is a valid IP address - * - * @param mixed $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - if (ip2long($valueString) === false) { - $this->_error(); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/LessThan.php b/phpQuery/phpQuery/Zend/Validate/LessThan.php deleted file mode 100644 index 9f7b72c..0000000 --- a/phpQuery/phpQuery/Zend/Validate/LessThan.php +++ /dev/null @@ -1,113 +0,0 @@ - "'%value%' is not less than '%max%'" - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'max' => '_max' - ); - - /** - * Maximum value - * - * @var mixed - */ - protected $_max; - - /** - * Sets validator options - * - * @param mixed $max - * @return void - */ - public function __construct($max) - { - $this->setMax($max); - } - - /** - * Returns the max option - * - * @return mixed - */ - public function getMax() - { - return $this->_max; - } - - /** - * Sets the max option - * - * @param mixed $max - * @return Zend_Validate_LessThan Provides a fluent interface - */ - public function setMax($max) - { - $this->_max = $max; - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is less than max option - * - * @param mixed $value - * @return boolean - */ - public function isValid($value) - { - $this->_setValue($value); - if ($this->_max <= $value) { - $this->_error(); - return false; - } - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/NotEmpty.php b/phpQuery/phpQuery/Zend/Validate/NotEmpty.php deleted file mode 100644 index dcf3662..0000000 --- a/phpQuery/phpQuery/Zend/Validate/NotEmpty.php +++ /dev/null @@ -1,74 +0,0 @@ - "Value is empty, but a non-empty value is required" - ); - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value is not an empty value. - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $this->_setValue((string) $value); - - if (is_string($value) - && (('' === $value) - || preg_match('/^\s+$/s', $value)) - ) { - $this->_error(); - return false; - } elseif (!is_string($value) && empty($value)) { - $this->_error(); - return false; - } - - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/Regex.php b/phpQuery/phpQuery/Zend/Validate/Regex.php deleted file mode 100644 index 1566f07..0000000 --- a/phpQuery/phpQuery/Zend/Validate/Regex.php +++ /dev/null @@ -1,125 +0,0 @@ - "'%value%' does not match against pattern '%pattern%'" - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'pattern' => '_pattern' - ); - - /** - * Regular expression pattern - * - * @var string - */ - protected $_pattern; - - /** - * Sets validator options - * - * @param string $pattern - * @return void - */ - public function __construct($pattern) - { - $this->setPattern($pattern); - } - - /** - * Returns the pattern option - * - * @return string - */ - public function getPattern() - { - return $this->_pattern; - } - - /** - * Sets the pattern option - * - * @param string $pattern - * @return Zend_Validate_Regex Provides a fluent interface - */ - public function setPattern($pattern) - { - $this->_pattern = (string) $pattern; - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if $value matches against the pattern option - * - * @param string $value - * @throws Zend_Validate_Exception if there is a fatal error in pattern matching - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - - $this->_setValue($valueString); - - $status = @preg_match($this->_pattern, $valueString); - if (false === $status) { - /** - * @see Zend_Validate_Exception - */ - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("Internal error matching pattern '$this->_pattern' against value '$valueString'"); - } - if (!$status) { - $this->_error(); - return false; - } - return true; - } - -} diff --git a/phpQuery/phpQuery/Zend/Validate/StringLength.php b/phpQuery/phpQuery/Zend/Validate/StringLength.php deleted file mode 100644 index c43f2ca..0000000 --- a/phpQuery/phpQuery/Zend/Validate/StringLength.php +++ /dev/null @@ -1,180 +0,0 @@ - "'%value%' is less than %min% characters long", - self::TOO_LONG => "'%value%' is greater than %max% characters long" - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'min' => '_min', - 'max' => '_max' - ); - - /** - * Minimum length - * - * @var integer - */ - protected $_min; - - /** - * Maximum length - * - * If null, there is no maximum length - * - * @var integer|null - */ - protected $_max; - - /** - * Sets validator options - * - * @param integer $min - * @param integer $max - * @return void - */ - public function __construct($min = 0, $max = null) - { - $this->setMin($min); - $this->setMax($max); - } - - /** - * Returns the min option - * - * @return integer - */ - public function getMin() - { - return $this->_min; - } - - /** - * Sets the min option - * - * @param integer $min - * @throws Zend_Validate_Exception - * @return Zend_Validate_StringLength Provides a fluent interface - */ - public function setMin($min) - { - if (null !== $this->_max && $min > $this->_max) { - /** - * @see Zend_Validate_Exception - */ - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum length, but $min >" - . " $this->_max"); - } - $this->_min = max(0, (integer) $min); - return $this; - } - - /** - * Returns the max option - * - * @return integer|null - */ - public function getMax() - { - return $this->_max; - } - - /** - * Sets the max option - * - * @param integer|null $max - * @throws Zend_Validate_Exception - * @return Zend_Validate_StringLength Provides a fluent interface - */ - public function setMax($max) - { - if (null === $max) { - $this->_max = null; - } else if ($max < $this->_min) { - /** - * @see Zend_Validate_Exception - */ - require_once 'Zend/Validate/Exception.php'; - throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum length, but " - . "$max < $this->_min"); - } else { - $this->_max = (integer) $max; - } - - return $this; - } - - /** - * Defined by Zend_Validate_Interface - * - * Returns true if and only if the string length of $value is at least the min option and - * no greater than the max option (when the max option is not null). - * - * @param string $value - * @return boolean - */ - public function isValid($value) - { - $valueString = (string) $value; - $this->_setValue($valueString); - $length = iconv_strlen($valueString); - if ($length < $this->_min) { - $this->_error(self::TOO_SHORT); - } - if (null !== $this->_max && $this->_max < $length) { - $this->_error(self::TOO_LONG); - } - if (count($this->_messages)) { - return false; - } else { - return true; - } - } - -} diff --git a/phpQuery/phpQuery/bootstrap.example.php b/phpQuery/phpQuery/bootstrap.example.php deleted file mode 100644 index 4fafe1a..0000000 --- a/phpQuery/phpQuery/bootstrap.example.php +++ /dev/null @@ -1,14 +0,0 @@ - \ No newline at end of file diff --git a/phpQuery/phpQuery/compat/mbstring.php b/phpQuery/phpQuery/compat/mbstring.php deleted file mode 100644 index 409129e..0000000 --- a/phpQuery/phpQuery/compat/mbstring.php +++ /dev/null @@ -1,88 +0,0 @@ -document) - $pq->find('*')->add($pq->document) - ->trigger($type, $data); - } - } else { - if (isset($data[0]) && $data[0] instanceof DOMEvent) { - $event = $data[0]; - $event->relatedTarget = $event->target; - $event->target = $node; - $data = array_slice($data, 1); - } else { - $event = new DOMEvent(array( - 'type' => $type, - 'target' => $node, - 'timeStamp' => time(), - )); - } - $i = 0; - while($node) { - // TODO whois - phpQuery::debug("Triggering ".($i?"bubbled ":'')."event '{$type}' on " - ."node \n");//.phpQueryObject::whois($node)."\n"); - $event->currentTarget = $node; - $eventNode = self::getNode($documentID, $node); - if (isset($eventNode->eventHandlers)) { - foreach($eventNode->eventHandlers as $eventType => $handlers) { - $eventNamespace = null; - if (strpos($type, '.') !== false) - list($eventName, $eventNamespace) = explode('.', $eventType); - else - $eventName = $eventType; - if ($name != $eventName) - continue; - if ($namespace && $eventNamespace && $namespace != $eventNamespace) - continue; - foreach($handlers as $handler) { - phpQuery::debug("Calling event handler\n"); - $event->data = $handler['data'] - ? $handler['data'] - : null; - $params = array_merge(array($event), $data); - $return = phpQuery::callbackRun($handler['callback'], $params); - if ($return === false) { - $event->bubbles = false; - } - } - } - } - // to bubble or not to bubble... - if (! $event->bubbles) - break; - $node = $node->parentNode; - $i++; - } - } - } - /** - * Binds a handler to one or more events (like click) for each matched element. - * Can also bind custom events. - * - * @param DOMNode|phpQueryObject|string $document - * @param unknown_type $type - * @param unknown_type $data Optional - * @param unknown_type $callback - * - * @TODO support '!' (exclusive) events - * @TODO support more than event in $type (space-separated) - * @TODO support binding to global events - */ - public static function add($document, $node, $type, $data, $callback = null) { - phpQuery::debug("Binding '$type' event"); - $documentID = phpQuery::getDocumentID($document); -// if (is_null($callback) && is_callable($data)) { -// $callback = $data; -// $data = null; -// } - $eventNode = self::getNode($documentID, $node); - if (! $eventNode) - $eventNode = self::setNode($documentID, $node); - if (!isset($eventNode->eventHandlers[$type])) - $eventNode->eventHandlers[$type] = array(); - $eventNode->eventHandlers[$type][] = array( - 'callback' => $callback, - 'data' => $data, - ); - } - /** - * Enter description here... - * - * @param DOMNode|phpQueryObject|string $document - * @param unknown_type $type - * @param unknown_type $callback - * - * @TODO namespace events - * @TODO support more than event in $type (space-separated) - */ - public static function remove($document, $node, $type = null, $callback = null) { - $documentID = phpQuery::getDocumentID($document); - $eventNode = self::getNode($documentID, $node); - if (is_object($eventNode) && isset($eventNode->eventHandlers[$type])) { - if ($callback) { - foreach($eventNode->eventHandlers[$type] as $k => $handler) - if ($handler['callback'] == $callback) - unset($eventNode->eventHandlers[$type][$k]); - } else { - unset($eventNode->eventHandlers[$type]); - } - } - } - protected static function getNode($documentID, $node) { - foreach(phpQuery::$documents[$documentID]->eventsNodes as $eventNode) { - if ($node->isSameNode($eventNode)) - return $eventNode; - } - } - protected static function setNode($documentID, $node) { - phpQuery::$documents[$documentID]->eventsNodes[] = $node; - return phpQuery::$documents[$documentID]->eventsNodes[ - count(phpQuery::$documents[$documentID]->eventsNodes)-1 - ]; - } - protected static function issetGlobal($documentID, $type) { - return isset(phpQuery::$documents[$documentID]) - ? in_array($type, phpQuery::$documents[$documentID]->eventsGlobal) - : false; - } -} diff --git a/phpQuery/phpQuery/phpQueryObject.php b/phpQuery/phpQuery/phpQueryObject.php deleted file mode 100644 index 146ddc8..0000000 --- a/phpQuery/phpQuery/phpQueryObject.php +++ /dev/null @@ -1,3180 +0,0 @@ - - * @package phpQuery - * @method phpQueryObject clone() clone() - * @method phpQueryObject empty() empty() - * @method phpQueryObject next() next($selector = null) - * @method phpQueryObject prev() prev($selector = null) - * @property Int $length - */ -class phpQueryObject - implements Iterator, Countable, ArrayAccess { - public $documentID = null; - /** - * DOMDocument class. - * - * @var DOMDocument - */ - public $document = null; - public $charset = null; - /** - * - * @var DOMDocumentWrapper - */ - public $documentWrapper = null; - /** - * XPath interface. - * - * @var DOMXPath - */ - public $xpath = null; - /** - * Stack of selected elements. - * @TODO refactor to ->nodes - * @var array - */ - public $elements = array(); - /** - * @access private - */ - protected $elementsBackup = array(); - /** - * @access private - */ - protected $previous = null; - /** - * @access private - * @TODO deprecate - */ - protected $root = array(); - /** - * Indicated if doument is just a fragment (no tag). - * - * Every document is realy a full document, so even documentFragments can - * be queried against , but getDocument(id)->htmlOuter() will return - * only contents of . - * - * @var bool - */ - public $documentFragment = true; - /** - * Iterator interface helper - * @access private - */ - protected $elementsInterator = array(); - /** - * Iterator interface helper - * @access private - */ - protected $valid = false; - /** - * Iterator interface helper - * @access private - */ - protected $current = null; - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function __construct($documentID) { -// if ($documentID instanceof self) -// var_dump($documentID->getDocumentID()); - $id = $documentID instanceof self - ? $documentID->getDocumentID() - : $documentID; -// var_dump($id); - if (! isset(phpQuery::$documents[$id] )) { -// var_dump(phpQuery::$documents); - throw new Exception("Document with ID '{$id}' isn't loaded. Use phpQuery::newDocument(\$html) or phpQuery::newDocumentFile(\$file) first."); - } - $this->documentID = $id; - $this->documentWrapper =& phpQuery::$documents[$id]; - $this->document =& $this->documentWrapper->document; - $this->xpath =& $this->documentWrapper->xpath; - $this->charset =& $this->documentWrapper->charset; - $this->documentFragment =& $this->documentWrapper->isDocumentFragment; - // TODO check $this->DOM->documentElement; -// $this->root = $this->document->documentElement; - $this->root =& $this->documentWrapper->root; -// $this->toRoot(); - $this->elements = array($this->root); - } - /** - * - * @access private - * @param $attr - * @return unknown_type - */ - public function __get($attr) { - switch($attr) { - // FIXME doesnt work at all ? - case 'length': - return $this->size(); - break; - default: - return $this->$attr; - } - } - /** - * Saves actual object to $var by reference. - * Useful when need to break chain. - * @param phpQueryObject $var - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function toReference(&$var) { - return $var = $this; - } - public function documentFragment($state = null) { - if ($state) { - phpQuery::$documents[$this->getDocumentID()]['documentFragment'] = $state; - return $this; - } - return $this->documentFragment; - } - /** - * @access private - * @TODO documentWrapper - */ - protected function isRoot( $node) { -// return $node instanceof DOMDOCUMENT || $node->tagName == 'html'; - return $node instanceof DOMDOCUMENT - || ($node instanceof DOMELEMENT && $node->tagName == 'html') - || $this->root->isSameNode($node); - } - /** - * @access private - */ - protected function stackIsRoot() { - return $this->size() == 1 && $this->isRoot($this->elements[0]); - } - /** - * Enter description here... - * NON JQUERY METHOD - * - * Watch out, it doesn't creates new instance, can be reverted with end(). - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function toRoot() { - $this->elements = array($this->root); - return $this; -// return $this->newInstance(array($this->root)); - } - /** - * Saves object's DocumentID to $var by reference. - * - * $myDocumentId; - * phpQuery::newDocument('
') - * ->getDocumentIDRef($myDocumentId) - * ->find('div')->... - * - * - * @param unknown_type $domId - * @see phpQuery::newDocument - * @see phpQuery::newDocumentFile - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function getDocumentIDRef(&$documentID) { - $documentID = $this->getDocumentID(); - return $this; - } - /** - * Returns object with stack set to document root. - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function getDocument() { - return phpQuery::getDocument($this->getDocumentID()); - } - /** - * - * @return DOMDocument - */ - public function getDOMDocument() { - return $this->document; - } - /** - * Get object's Document ID. - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function getDocumentID() { - return $this->documentID; - } - /** - * Unloads whole document from memory. - * CAUTION! None further operations will be possible on this document. - * All objects refering to it will be useless. - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function unloadDocument() { - phpQuery::unloadDocuments($this->getDocumentID()); - } - public function isHTML() { - return $this->documentWrapper->isHTML; - } - public function isXHTML() { - return $this->documentWrapper->isXHTML; - } - public function isXML() { - return $this->documentWrapper->isXML; - } - /** - * Enter description here... - * - * @link http://docs.jquery.com/Ajax/serialize - * @return string - */ - public function serialize() { - return phpQuery::param($this->serializeArray()); - } - /** - * Enter description here... - * - * @link http://docs.jquery.com/Ajax/serializeArray - * @return array - */ - public function serializeArray($submit = null) { - $source = $this->filter('form, input, select, textarea') - ->find('input, select, textarea') - ->andSelf() - ->not('form'); - $return = array(); -// $source->dumpDie(); - foreach($source as $input) { - $input = phpQuery::pq($input); - if ($input->is('[disabled]')) - continue; - if (!$input->is('[name]')) - continue; - if ($input->is('[type=checkbox]') && !$input->is('[checked]')) - continue; - // jquery diff - if ($submit && $input->is('[type=submit]')) { - if ($submit instanceof DOMELEMENT && ! $input->elements[0]->isSameNode($submit)) - continue; - else if (is_string($submit) && $input->attr('name') != $submit) - continue; - } - $return[] = array( - 'name' => $input->attr('name'), - 'value' => $input->val(), - ); - } - return $return; - } - /** - * @access private - */ - protected function debug($in) { - if (! phpQuery::$debug ) - return; - print('
');
-		print_r($in);
-		// file debug
-//		file_put_contents(dirname(__FILE__).'/phpQuery.log', print_r($in, true)."\n", FILE_APPEND);
-		// quite handy debug trace
-//		if ( is_array($in))
-//			print_r(array_slice(debug_backtrace(), 3));
-		print("
\n"); - } - /** - * @access private - */ - protected function isRegexp($pattern) { - return in_array( - $pattern[ mb_strlen($pattern)-1 ], - array('^','*','$') - ); - } - /** - * Determines if $char is really a char. - * - * @param string $char - * @return bool - * @todo rewrite me to charcode range ! ;) - * @access private - */ - protected function isChar($char) { - return extension_loaded('mbstring') && phpQuery::$mbstringSupport - ? mb_eregi('\w', $char) - : preg_match('@\w@', $char); - } - /** - * @access private - */ - protected function parseSelector($query) { - // clean spaces - // TODO include this inside parsing ? - $query = trim( - preg_replace('@\s+@', ' ', - preg_replace('@\s*(>|\\+|~)\s*@', '\\1', $query) - ) - ); - $queries = array(array()); - if (! $query) - return $queries; - $return =& $queries[0]; - $specialChars = array('>',' '); -// $specialCharsMapping = array('/' => '>'); - $specialCharsMapping = array(); - $strlen = mb_strlen($query); - $classChars = array('.', '-'); - $pseudoChars = array('-'); - $tagChars = array('*', '|', '-'); - // split multibyte string - // http://code.google.com/p/phpquery/issues/detail?id=76 - $_query = array(); - for ($i=0; $i<$strlen; $i++) - $_query[] = mb_substr($query, $i, 1); - $query = $_query; - // it works, but i dont like it... - $i = 0; - while( $i < $strlen) { - $c = $query[$i]; - $tmp = ''; - // TAG - if ($this->isChar($c) || in_array($c, $tagChars)) { - while(isset($query[$i]) - && ($this->isChar($query[$i]) || in_array($query[$i], $tagChars))) { - $tmp .= $query[$i]; - $i++; - } - $return[] = $tmp; - // IDs - } else if ( $c == '#') { - $i++; - while( isset($query[$i]) && ($this->isChar($query[$i]) || $query[$i] == '-')) { - $tmp .= $query[$i]; - $i++; - } - $return[] = '#'.$tmp; - // SPECIAL CHARS - } else if (in_array($c, $specialChars)) { - $return[] = $c; - $i++; - // MAPPED SPECIAL MULTICHARS -// } else if ( $c.$query[$i+1] == '//') { -// $return[] = ' '; -// $i = $i+2; - // MAPPED SPECIAL CHARS - } else if ( isset($specialCharsMapping[$c])) { - $return[] = $specialCharsMapping[$c]; - $i++; - // COMMA - } else if ( $c == ',') { - $queries[] = array(); - $return =& $queries[ count($queries)-1 ]; - $i++; - while( isset($query[$i]) && $query[$i] == ' ') - $i++; - // CLASSES - } else if ($c == '.') { - while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $classChars))) { - $tmp .= $query[$i]; - $i++; - } - $return[] = $tmp; - // ~ General Sibling Selector - } else if ($c == '~') { - $spaceAllowed = true; - $tmp .= $query[$i++]; - while( isset($query[$i]) - && ($this->isChar($query[$i]) - || in_array($query[$i], $classChars) - || $query[$i] == '*' - || ($query[$i] == ' ' && $spaceAllowed) - )) { - if ($query[$i] != ' ') - $spaceAllowed = false; - $tmp .= $query[$i]; - $i++; - } - $return[] = $tmp; - // + Adjacent sibling selectors - } else if ($c == '+') { - $spaceAllowed = true; - $tmp .= $query[$i++]; - while( isset($query[$i]) - && ($this->isChar($query[$i]) - || in_array($query[$i], $classChars) - || $query[$i] == '*' - || ($spaceAllowed && $query[$i] == ' ') - )) { - if ($query[$i] != ' ') - $spaceAllowed = false; - $tmp .= $query[$i]; - $i++; - } - $return[] = $tmp; - // ATTRS - } else if ($c == '[') { - $stack = 1; - $tmp .= $c; - while( isset($query[++$i])) { - $tmp .= $query[$i]; - if ( $query[$i] == '[') { - $stack++; - } else if ( $query[$i] == ']') { - $stack--; - if (! $stack ) - break; - } - } - $return[] = $tmp; - $i++; - // PSEUDO CLASSES - } else if ($c == ':') { - $stack = 1; - $tmp .= $query[$i++]; - while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $pseudoChars))) { - $tmp .= $query[$i]; - $i++; - } - // with arguments ? - if ( isset($query[$i]) && $query[$i] == '(') { - $tmp .= $query[$i]; - $stack = 1; - while( isset($query[++$i])) { - $tmp .= $query[$i]; - if ( $query[$i] == '(') { - $stack++; - } else if ( $query[$i] == ')') { - $stack--; - if (! $stack ) - break; - } - } - $return[] = $tmp; - $i++; - } else { - $return[] = $tmp; - } - } else { - $i++; - } - } - foreach($queries as $k => $q) { - if (isset($q[0])) { - if (isset($q[0][0]) && $q[0][0] == ':') - array_unshift($queries[$k], '*'); - if ($q[0] != '>') - array_unshift($queries[$k], ' '); - } - } - return $queries; - } - /** - * Return matched DOM nodes. - * - * @param int $index - * @return array|DOMElement Single DOMElement or array of DOMElement. - */ - public function get($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { - $return = isset($index) - ? (isset($this->elements[$index]) ? $this->elements[$index] : null) - : $this->elements; - // pass thou callbacks - $args = func_get_args(); - $args = array_slice($args, 1); - foreach($args as $callback) { - if (is_array($return)) - foreach($return as $k => $v) - $return[$k] = phpQuery::callbackRun($callback, array($v)); - else - $return = phpQuery::callbackRun($callback, array($return)); - } - return $return; - } - /** - * Return matched DOM nodes. - * jQuery difference. - * - * @param int $index - * @return array|string Returns string if $index != null - * @todo implement callbacks - * @todo return only arrays ? - * @todo maybe other name... - */ - public function getString($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { - if ($index) - $return = $this->eq($index)->text(); - else { - $return = array(); - for($i = 0; $i < $this->size(); $i++) { - $return[] = $this->eq($i)->text(); - } - } - // pass thou callbacks - $args = func_get_args(); - $args = array_slice($args, 1); - foreach($args as $callback) { - $return = phpQuery::callbackRun($callback, array($return)); - } - return $return; - } - /** - * Return matched DOM nodes. - * jQuery difference. - * - * @param int $index - * @return array|string Returns string if $index != null - * @todo implement callbacks - * @todo return only arrays ? - * @todo maybe other name... - */ - public function getStrings($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { - if ($index) - $return = $this->eq($index)->text(); - else { - $return = array(); - for($i = 0; $i < $this->size(); $i++) { - $return[] = $this->eq($i)->text(); - } - // pass thou callbacks - $args = func_get_args(); - $args = array_slice($args, 1); - } - foreach($args as $callback) { - if (is_array($return)) - foreach($return as $k => $v) - $return[$k] = phpQuery::callbackRun($callback, array($v)); - else - $return = phpQuery::callbackRun($callback, array($return)); - } - return $return; - } - /** - * Returns new instance of actual class. - * - * @param array $newStack Optional. Will replace old stack with new and move old one to history.c - */ - public function newInstance($newStack = null) { - $class = get_class($this); - // support inheritance by passing old object to overloaded constructor - $new = $class != 'phpQuery' - ? new $class($this, $this->getDocumentID()) - : new phpQueryObject($this->getDocumentID()); - $new->previous = $this; - if (is_null($newStack)) { - $new->elements = $this->elements; - if ($this->elementsBackup) - $this->elements = $this->elementsBackup; - } else if (is_string($newStack)) { - $new->elements = phpQuery::pq($newStack, $this->getDocumentID())->stack(); - } else { - $new->elements = $newStack; - } - return $new; - } - /** - * Enter description here... - * - * In the future, when PHP will support XLS 2.0, then we would do that this way: - * contains(tokenize(@class, '\s'), "something") - * @param unknown_type $class - * @param unknown_type $node - * @return boolean - * @access private - */ - protected function matchClasses($class, $node) { - // multi-class - if ( mb_strpos($class, '.', 1)) { - $classes = explode('.', substr($class, 1)); - $classesCount = count( $classes ); - $nodeClasses = explode(' ', $node->getAttribute('class') ); - $nodeClassesCount = count( $nodeClasses ); - if ( $classesCount > $nodeClassesCount ) - return false; - $diff = count( - array_diff( - $classes, - $nodeClasses - ) - ); - if (! $diff ) - return true; - // single-class - } else { - return in_array( - // strip leading dot from class name - substr($class, 1), - // get classes for element as array - explode(' ', $node->getAttribute('class') ) - ); - } - } - /** - * @access private - */ - protected function runQuery($XQuery, $selector = null, $compare = null) { - if ($compare && ! method_exists($this, $compare)) - return false; - $stack = array(); - if (! $this->elements) - $this->debug('Stack empty, skipping...'); -// var_dump($this->elements[0]->nodeType); - // element, document - foreach($this->stack(array(1, 9, 13)) as $k => $stackNode) { - $detachAfter = false; - // to work on detached nodes we need temporary place them somewhere - // thats because context xpath queries sucks ;] - $testNode = $stackNode; - while ($testNode) { - if (! $testNode->parentNode && ! $this->isRoot($testNode)) { - $this->root->appendChild($testNode); - $detachAfter = $testNode; - break; - } - $testNode = isset($testNode->parentNode) - ? $testNode->parentNode - : null; - } - // XXX tmp ? - $xpath = $this->documentWrapper->isXHTML - ? $this->getNodeXpath($stackNode, 'html') - : $this->getNodeXpath($stackNode); - // FIXME pseudoclasses-only query, support XML - $query = $XQuery == '//' && $xpath == '/html[1]' - ? '//*' - : $xpath.$XQuery; - $this->debug("XPATH: {$query}"); - // run query, get elements - $nodes = $this->xpath->query($query); - $this->debug("QUERY FETCHED"); - if (! $nodes->length ) - $this->debug('Nothing found'); - $debug = array(); - foreach($nodes as $node) { - $matched = false; - if ( $compare) { - phpQuery::$debug ? - $this->debug("Found: ".$this->whois( $node ).", comparing with {$compare}()") - : null; - $phpQueryDebug = phpQuery::$debug; - phpQuery::$debug = false; - // TODO ??? use phpQuery::callbackRun() - if (call_user_func_array(array($this, $compare), array($selector, $node))) - $matched = true; - phpQuery::$debug = $phpQueryDebug; - } else { - $matched = true; - } - if ( $matched) { - if (phpQuery::$debug) - $debug[] = $this->whois( $node ); - $stack[] = $node; - } - } - if (phpQuery::$debug) { - $this->debug("Matched ".count($debug).": ".implode(', ', $debug)); - } - if ($detachAfter) - $this->root->removeChild($detachAfter); - } - $this->elements = $stack; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function find($selectors, $context = null, $noHistory = false) { - if (!$noHistory) - // backup last stack /for end()/ - $this->elementsBackup = $this->elements; - // allow to define context - // TODO combine code below with phpQuery::pq() context guessing code - // as generic function - if ($context) { - if (! is_array($context) && $context instanceof DOMELEMENT) - $this->elements = array($context); - else if (is_array($context)) { - $this->elements = array(); - foreach ($context as $c) - if ($c instanceof DOMELEMENT) - $this->elements[] = $c; - } else if ( $context instanceof self ) - $this->elements = $context->elements; - } - $queries = $this->parseSelector($selectors); - $this->debug(array('FIND', $selectors, $queries)); - $XQuery = ''; - // remember stack state because of multi-queries - $oldStack = $this->elements; - // here we will be keeping found elements - $stack = array(); - foreach($queries as $selector) { - $this->elements = $oldStack; - $delimiterBefore = false; - foreach($selector as $s) { - // TAG - $isTag = extension_loaded('mbstring') && phpQuery::$mbstringSupport - ? mb_ereg_match('^[\w|\||-]+$', $s) || $s == '*' - : preg_match('@^[\w|\||-]+$@', $s) || $s == '*'; - if ($isTag) { - if ($this->isXML()) { - // namespace support - if (mb_strpos($s, '|') !== false) { - $ns = $tag = null; - list($ns, $tag) = explode('|', $s); - $XQuery .= "$ns:$tag"; - } else if ($s == '*') { - $XQuery .= "*"; - } else { - $XQuery .= "*[local-name()='$s']"; - } - } else { - $XQuery .= $s; - } - // ID - } else if ($s[0] == '#') { - if ($delimiterBefore) - $XQuery .= '*'; - $XQuery .= "[@id='".substr($s, 1)."']"; - // ATTRIBUTES - } else if ($s[0] == '[') { - if ($delimiterBefore) - $XQuery .= '*'; - // strip side brackets - $attr = trim($s, ']['); - $execute = false; - // attr with specifed value - if (mb_strpos($s, '=')) { - $value = null; - list($attr, $value) = explode('=', $attr); - $value = trim($value, "'\""); - if ($this->isRegexp($attr)) { - // cut regexp character - $attr = substr($attr, 0, -1); - $execute = true; - $XQuery .= "[@{$attr}]"; - } else { - $XQuery .= "[@{$attr}='{$value}']"; - } - // attr without specified value - } else { - $XQuery .= "[@{$attr}]"; - } - if ($execute) { - $this->runQuery($XQuery, $s, 'is'); - $XQuery = ''; - if (! $this->length()) - break; - } - // CLASSES - } else if ($s[0] == '.') { - // TODO use return $this->find("./self::*[contains(concat(\" \",@class,\" \"), \" $class \")]"); - // thx wizDom ;) - if ($delimiterBefore) - $XQuery .= '*'; - $XQuery .= '[@class]'; - $this->runQuery($XQuery, $s, 'matchClasses'); - $XQuery = ''; - if (! $this->length() ) - break; - // ~ General Sibling Selector - } else if ($s[0] == '~') { - $this->runQuery($XQuery); - $XQuery = ''; - $this->elements = $this - ->siblings( - substr($s, 1) - )->elements; - if (! $this->length() ) - break; - // + Adjacent sibling selectors - } else if ($s[0] == '+') { - // TODO /following-sibling:: - $this->runQuery($XQuery); - $XQuery = ''; - $subSelector = substr($s, 1); - $subElements = $this->elements; - $this->elements = array(); - foreach($subElements as $node) { - // search first DOMElement sibling - $test = $node->nextSibling; - while($test && ! ($test instanceof DOMELEMENT)) - $test = $test->nextSibling; - if ($test && $this->is($subSelector, $test)) - $this->elements[] = $test; - } - if (! $this->length() ) - break; - // PSEUDO CLASSES - } else if ($s[0] == ':') { - // TODO optimization for :first :last - if ($XQuery) { - $this->runQuery($XQuery); - $XQuery = ''; - } - if (! $this->length()) - break; - $this->pseudoClasses($s); - if (! $this->length()) - break; - // DIRECT DESCENDANDS - } else if ($s == '>') { - $XQuery .= '/'; - $delimiterBefore = 2; - // ALL DESCENDANDS - } else if ($s == ' ') { - $XQuery .= '//'; - $delimiterBefore = 2; - // ERRORS - } else { - phpQuery::debug("Unrecognized token '$s'"); - } - $delimiterBefore = $delimiterBefore === 2; - } - // run query if any - if ($XQuery && $XQuery != '//') { - $this->runQuery($XQuery); - $XQuery = ''; - } - foreach($this->elements as $node) - if (! $this->elementsContainsNode($node, $stack)) - $stack[] = $node; - } - $this->elements = $stack; - return $this->newInstance(); - } - /** - * @todo create API for classes with pseudoselectors - * @access private - */ - protected function pseudoClasses($class) { - // TODO clean args parsing ? - $class = ltrim($class, ':'); - $haveArgs = mb_strpos($class, '('); - if ($haveArgs !== false) { - $args = substr($class, $haveArgs+1, -1); - $class = substr($class, 0, $haveArgs); - } - switch($class) { - case 'even': - case 'odd': - $stack = array(); - foreach($this->elements as $i => $node) { - if ($class == 'even' && ($i%2) == 0) - $stack[] = $node; - else if ( $class == 'odd' && $i % 2 ) - $stack[] = $node; - } - $this->elements = $stack; - break; - case 'eq': - $k = intval($args); - $this->elements = isset( $this->elements[$k] ) - ? array( $this->elements[$k] ) - : array(); - break; - case 'gt': - $this->elements = array_slice($this->elements, $args+1); - break; - case 'lt': - $this->elements = array_slice($this->elements, 0, $args+1); - break; - case 'first': - if (isset($this->elements[0])) - $this->elements = array($this->elements[0]); - break; - case 'last': - if ($this->elements) - $this->elements = array($this->elements[count($this->elements)-1]); - break; - /*case 'parent': - $stack = array(); - foreach($this->elements as $node) { - if ( $node->childNodes->length ) - $stack[] = $node; - } - $this->elements = $stack; - break;*/ - case 'contains': - $text = trim($args, "\"'"); - $stack = array(); - foreach($this->elements as $node) { - if (mb_stripos($node->textContent, $text) === false) - continue; - $stack[] = $node; - } - $this->elements = $stack; - break; - case 'not': - $selector = self::unQuote($args); - $this->elements = $this->not($selector)->stack(); - break; - case 'slice': - // TODO jQuery difference ? - $args = explode(',', - str_replace(', ', ',', trim($args, "\"'")) - ); - $start = $args[0]; - $end = isset($args[1]) - ? $args[1] - : null; - if ($end > 0) - $end = $end-$start; - $this->elements = array_slice($this->elements, $start, $end); - break; - case 'has': - $selector = trim($args, "\"'"); - $stack = array(); - foreach($this->stack(1) as $el) { - if ($this->find($selector, $el, true)->length) - $stack[] = $el; - } - $this->elements = $stack; - break; - case 'submit': - case 'reset': - $this->elements = phpQuery::merge( - $this->map(array($this, 'is'), - "input[type=$class]", new CallbackParam() - ), - $this->map(array($this, 'is'), - "button[type=$class]", new CallbackParam() - ) - ); - break; -// $stack = array(); -// foreach($this->elements as $node) -// if ($node->is('input[type=submit]') || $node->is('button[type=submit]')) -// $stack[] = $el; -// $this->elements = $stack; - case 'input': - $this->elements = $this->map( - array($this, 'is'), - 'input', new CallbackParam() - )->elements; - break; - case 'password': - case 'checkbox': - case 'radio': - case 'hidden': - case 'image': - case 'file': - $this->elements = $this->map( - array($this, 'is'), - "input[type=$class]", new CallbackParam() - )->elements; - break; - case 'parent': - $this->elements = $this->map( - create_function('$node', ' - return $node instanceof DOMELEMENT && $node->childNodes->length - ? $node : null;') - )->elements; - break; - case 'empty': - $this->elements = $this->map( - create_function('$node', ' - return $node instanceof DOMELEMENT && $node->childNodes->length - ? null : $node;') - )->elements; - break; - case 'disabled': - case 'selected': - case 'checked': - $this->elements = $this->map( - array($this, 'is'), - "[$class]", new CallbackParam() - )->elements; - break; - case 'enabled': - $this->elements = $this->map( - create_function('$node', ' - return pq($node)->not(":disabled") ? $node : null;') - )->elements; - break; - case 'header': - $this->elements = $this->map( - create_function('$node', - '$isHeader = isset($node->tagName) && in_array($node->tagName, array( - "h1", "h2", "h3", "h4", "h5", "h6", "h7" - )); - return $isHeader - ? $node - : null;') - )->elements; -// $this->elements = $this->map( -// create_function('$node', '$node = pq($node); -// return $node->is("h1") -// || $node->is("h2") -// || $node->is("h3") -// || $node->is("h4") -// || $node->is("h5") -// || $node->is("h6") -// || $node->is("h7") -// ? $node -// : null;') -// )->elements; - break; - case 'only-child': - $this->elements = $this->map( - create_function('$node', - 'return pq($node)->siblings()->size() == 0 ? $node : null;') - )->elements; - break; - case 'first-child': - $this->elements = $this->map( - create_function('$node', 'return pq($node)->prevAll()->size() == 0 ? $node : null;') - )->elements; - break; - case 'last-child': - $this->elements = $this->map( - create_function('$node', 'return pq($node)->nextAll()->size() == 0 ? $node : null;') - )->elements; - break; - case 'nth-child': - $param = trim($args, "\"'"); - if (! $param) - break; - // nth-child(n+b) to nth-child(1n+b) - if ($param{0} == 'n') - $param = '1'.$param; - // :nth-child(index/even/odd/equation) - if ($param == 'even' || $param == 'odd') - $mapped = $this->map( - create_function('$node, $param', - '$index = pq($node)->prevAll()->size()+1; - if ($param == "even" && ($index%2) == 0) - return $node; - else if ($param == "odd" && $index%2 == 1) - return $node; - else - return null;'), - new CallbackParam(), $param - ); - else if (mb_strlen($param) > 1 && $param{1} == 'n') - // an+b - $mapped = $this->map( - create_function('$node, $param', - '$prevs = pq($node)->prevAll()->size(); - $index = 1+$prevs; - $b = mb_strlen($param) > 3 - ? $param{3} - : 0; - $a = $param{0}; - if ($b && $param{2} == "-") - $b = -$b; - if ($a > 0) { - return ($index-$b)%$a == 0 - ? $node - : null; - phpQuery::debug($a."*".floor($index/$a)."+$b-1 == ".($a*floor($index/$a)+$b-1)." ?= $prevs"); - return $a*floor($index/$a)+$b-1 == $prevs - ? $node - : null; - } else if ($a == 0) - return $index == $b - ? $node - : null; - else - // negative value - return $index <= $b - ? $node - : null; -// if (! $b) -// return $index%$a == 0 -// ? $node -// : null; -// else -// return ($index-$b)%$a == 0 -// ? $node -// : null; - '), - new CallbackParam(), $param - ); - else - // index - $mapped = $this->map( - create_function('$node, $index', - '$prevs = pq($node)->prevAll()->size(); - if ($prevs && $prevs == $index-1) - return $node; - else if (! $prevs && $index == 1) - return $node; - else - return null;'), - new CallbackParam(), $param - ); - $this->elements = $mapped->elements; - break; - default: - $this->debug("Unknown pseudoclass '{$class}', skipping..."); - } - } - /** - * @access private - */ - protected function __pseudoClassParam($paramsString) { - // TODO; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function is($selector, $nodes = null) { - phpQuery::debug(array("Is:", $selector)); - if (! $selector) - return false; - $oldStack = $this->elements; - $returnArray = false; - if ($nodes && is_array($nodes)) { - $this->elements = $nodes; - } else if ($nodes) - $this->elements = array($nodes); - $this->filter($selector, true); - $stack = $this->elements; - $this->elements = $oldStack; - if ($nodes) - return $stack ? $stack : null; - return (bool)count($stack); - } - /** - * Enter description here... - * jQuery difference. - * - * Callback: - * - $index int - * - $node DOMNode - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @link http://docs.jquery.com/Traversing/filter - */ - public function filterCallback($callback, $_skipHistory = false) { - if (! $_skipHistory) { - $this->elementsBackup = $this->elements; - $this->debug("Filtering by callback"); - } - $newStack = array(); - foreach($this->elements as $index => $node) { - $result = phpQuery::callbackRun($callback, array($index, $node)); - if (is_null($result) || (! is_null($result) && $result)) - $newStack[] = $node; - } - $this->elements = $newStack; - return $_skipHistory - ? $this - : $this->newInstance(); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @link http://docs.jquery.com/Traversing/filter - */ - public function filter($selectors, $_skipHistory = false) { - if ($selectors instanceof Callback OR $selectors instanceof Closure) - return $this->filterCallback($selectors, $_skipHistory); - if (! $_skipHistory) - $this->elementsBackup = $this->elements; - $notSimpleSelector = array(' ', '>', '~', '+', '/'); - if (! is_array($selectors)) - $selectors = $this->parseSelector($selectors); - if (! $_skipHistory) - $this->debug(array("Filtering:", $selectors)); - $finalStack = array(); - foreach($selectors as $selector) { - $stack = array(); - if (! $selector) - break; - // avoid first space or / - if (in_array($selector[0], $notSimpleSelector)) - $selector = array_slice($selector, 1); - // PER NODE selector chunks - foreach($this->stack() as $node) { - $break = false; - foreach($selector as $s) { - if (!($node instanceof DOMELEMENT)) { - // all besides DOMElement - if ( $s[0] == '[') { - $attr = trim($s, '[]'); - if ( mb_strpos($attr, '=')) { - list( $attr, $val ) = explode('=', $attr); - if ($attr == 'nodeType' && $node->nodeType != $val) - $break = true; - } - } else - $break = true; - } else { - // DOMElement only - // ID - if ( $s[0] == '#') { - if ( $node->getAttribute('id') != substr($s, 1) ) - $break = true; - // CLASSES - } else if ( $s[0] == '.') { - if (! $this->matchClasses( $s, $node ) ) - $break = true; - // ATTRS - } else if ( $s[0] == '[') { - // strip side brackets - $attr = trim($s, '[]'); - if (mb_strpos($attr, '=')) { - list($attr, $val) = explode('=', $attr); - $val = self::unQuote($val); - if ($attr == 'nodeType') { - if ($val != $node->nodeType) - $break = true; - } else if ($this->isRegexp($attr)) { - $val = extension_loaded('mbstring') && phpQuery::$mbstringSupport - ? quotemeta(trim($val, '"\'')) - : preg_quote(trim($val, '"\''), '@'); - // switch last character - switch( substr($attr, -1)) { - // quotemeta used insted of preg_quote - // http://code.google.com/p/phpquery/issues/detail?id=76 - case '^': - $pattern = '^'.$val; - break; - case '*': - $pattern = '.*'.$val.'.*'; - break; - case '$': - $pattern = '.*'.$val.'$'; - break; - } - // cut last character - $attr = substr($attr, 0, -1); - $isMatch = extension_loaded('mbstring') && phpQuery::$mbstringSupport - ? mb_ereg_match($pattern, $node->getAttribute($attr)) - : preg_match("@{$pattern}@", $node->getAttribute($attr)); - if (! $isMatch) - $break = true; - } else if ($node->getAttribute($attr) != $val) - $break = true; - } else if (! $node->hasAttribute($attr)) - $break = true; - // PSEUDO CLASSES - } else if ( $s[0] == ':') { - // skip - // TAG - } else if (trim($s)) { - if ($s != '*') { - // TODO namespaces - if (isset($node->tagName)) { - if ($node->tagName != $s) - $break = true; - } else if ($s == 'html' && ! $this->isRoot($node)) - $break = true; - } - // AVOID NON-SIMPLE SELECTORS - } else if (in_array($s, $notSimpleSelector)) { - $break = true; - $this->debug(array('Skipping non simple selector', $selector)); - } - } - if ($break) - break; - } - // if element passed all chunks of selector - add it to new stack - if (! $break ) - $stack[] = $node; - } - $tmpStack = $this->elements; - $this->elements = $stack; - // PER ALL NODES selector chunks - foreach($selector as $s) - // PSEUDO CLASSES - if ($s[0] == ':') - $this->pseudoClasses($s); - foreach($this->elements as $node) - // XXX it should be merged without duplicates - // but jQuery doesnt do that - $finalStack[] = $node; - $this->elements = $tmpStack; - } - $this->elements = $finalStack; - if ($_skipHistory) { - return $this; - } else { - $this->debug("Stack length after filter(): ".count($finalStack)); - return $this->newInstance(); - } - } - /** - * - * @param $value - * @return unknown_type - * @TODO implement in all methods using passed parameters - */ - protected static function unQuote($value) { - return $value[0] == '\'' || $value[0] == '"' - ? substr($value, 1, -1) - : $value; - } - /** - * Enter description here... - * - * @link http://docs.jquery.com/Ajax/load - * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo Support $selector - */ - public function load($url, $data = null, $callback = null) { - if ($data && ! is_array($data)) { - $callback = $data; - $data = null; - } - if (mb_strpos($url, ' ') !== false) { - $matches = null; - if (extension_loaded('mbstring') && phpQuery::$mbstringSupport) - mb_ereg('^([^ ]+) (.*)$', $url, $matches); - else - preg_match('^([^ ]+) (.*)$', $url, $matches); - $url = $matches[1]; - $selector = $matches[2]; - // FIXME this sucks, pass as callback param - $this->_loadSelector = $selector; - } - $ajax = array( - 'url' => $url, - 'type' => $data ? 'POST' : 'GET', - 'data' => $data, - 'complete' => $callback, - 'success' => array($this, '__loadSuccess') - ); - phpQuery::ajax($ajax); - return $this; - } - /** - * @access private - * @param $html - * @return unknown_type - */ - public function __loadSuccess($html) { - if ($this->_loadSelector) { - $html = phpQuery::newDocument($html)->find($this->_loadSelector); - unset($this->_loadSelector); - } - foreach($this->stack(1) as $node) { - phpQuery::pq($node, $this->getDocumentID()) - ->markup($html); - } - } - /** - * Enter description here... - * - * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo - */ - public function css() { - // TODO - return $this; - } - /** - * @todo - * - */ - public function show(){ - // TODO - return $this; - } - /** - * @todo - * - */ - public function hide(){ - // TODO - return $this; - } - /** - * Trigger a type of event on every matched element. - * - * @param unknown_type $type - * @param unknown_type $data - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @TODO support more than event in $type (space-separated) - */ - public function trigger($type, $data = array()) { - foreach($this->elements as $node) - phpQueryEvents::trigger($this->getDocumentID(), $type, $data, $node); - return $this; - } - /** - * This particular method triggers all bound event handlers on an element (for a specific event type) WITHOUT executing the browsers default actions. - * - * @param unknown_type $type - * @param unknown_type $data - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @TODO - */ - public function triggerHandler($type, $data = array()) { - // TODO; - } - /** - * Binds a handler to one or more events (like click) for each matched element. - * Can also bind custom events. - * - * @param unknown_type $type - * @param unknown_type $data Optional - * @param unknown_type $callback - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @TODO support '!' (exclusive) events - * @TODO support more than event in $type (space-separated) - */ - public function bind($type, $data, $callback = null) { - // TODO check if $data is callable, not using is_callable - if (! isset($callback)) { - $callback = $data; - $data = null; - } - foreach($this->elements as $node) - phpQueryEvents::add($this->getDocumentID(), $node, $type, $data, $callback); - return $this; - } - /** - * Enter description here... - * - * @param unknown_type $type - * @param unknown_type $callback - * @return unknown - * @TODO namespace events - * @TODO support more than event in $type (space-separated) - */ - public function unbind($type = null, $callback = null) { - foreach($this->elements as $node) - phpQueryEvents::remove($this->getDocumentID(), $node, $type, $callback); - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function change($callback = null) { - if ($callback) - return $this->bind('change', $callback); - return $this->trigger('change'); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function submit($callback = null) { - if ($callback) - return $this->bind('submit', $callback); - return $this->trigger('submit'); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function click($callback = null) { - if ($callback) - return $this->bind('click', $callback); - return $this->trigger('click'); - } - /** - * Enter description here... - * - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function wrapAllOld($wrapper) { - $wrapper = pq($wrapper)->_clone(); - if (! $wrapper->length() || ! $this->length() ) - return $this; - $wrapper->insertBefore($this->elements[0]); - $deepest = $wrapper->elements[0]; - while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT) - $deepest = $deepest->firstChild; - pq($deepest)->append($this); - return $this; - } - /** - * Enter description here... - * - * TODO testme... - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function wrapAll($wrapper) { - if (! $this->length()) - return $this; - return phpQuery::pq($wrapper, $this->getDocumentID()) - ->clone() - ->insertBefore($this->get(0)) - ->map(array($this, '___wrapAllCallback')) - ->append($this); - } - /** - * - * @param $node - * @return unknown_type - * @access private - */ - public function ___wrapAllCallback($node) { - $deepest = $node; - while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT) - $deepest = $deepest->firstChild; - return $deepest; - } - /** - * Enter description here... - * NON JQUERY METHOD - * - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function wrapAllPHP($codeBefore, $codeAfter) { - return $this - ->slice(0, 1) - ->beforePHP($codeBefore) - ->end() - ->slice(-1) - ->afterPHP($codeAfter) - ->end(); - } - /** - * Enter description here... - * - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function wrap($wrapper) { - foreach($this->stack() as $node) - phpQuery::pq($node, $this->getDocumentID())->wrapAll($wrapper); - return $this; - } - /** - * Enter description here... - * - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function wrapPHP($codeBefore, $codeAfter) { - foreach($this->stack() as $node) - phpQuery::pq($node, $this->getDocumentID())->wrapAllPHP($codeBefore, $codeAfter); - return $this; - } - /** - * Enter description here... - * - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function wrapInner($wrapper) { - foreach($this->stack() as $node) - phpQuery::pq($node, $this->getDocumentID())->contents()->wrapAll($wrapper); - return $this; - } - /** - * Enter description here... - * - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function wrapInnerPHP($codeBefore, $codeAfter) { - foreach($this->stack(1) as $node) - phpQuery::pq($node, $this->getDocumentID())->contents() - ->wrapAllPHP($codeBefore, $codeAfter); - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @testme Support for text nodes - */ - public function contents() { - $stack = array(); - foreach($this->stack(1) as $el) { - // FIXME (fixed) http://code.google.com/p/phpquery/issues/detail?id=56 -// if (! isset($el->childNodes)) -// continue; - foreach($el->childNodes as $node) { - $stack[] = $node; - } - } - return $this->newInstance($stack); - } - /** - * Enter description here... - * - * jQuery difference. - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function contentsUnwrap() { - foreach($this->stack(1) as $node) { - if (! $node->parentNode ) - continue; - $childNodes = array(); - // any modification in DOM tree breaks childNodes iteration, so cache them first - foreach($node->childNodes as $chNode ) - $childNodes[] = $chNode; - foreach($childNodes as $chNode ) -// $node->parentNode->appendChild($chNode); - $node->parentNode->insertBefore($chNode, $node); - $node->parentNode->removeChild($node); - } - return $this; - } - /** - * Enter description here... - * - * jQuery difference. - */ - public function switchWith($markup) { - $markup = pq($markup, $this->getDocumentID()); - $content = null; - foreach($this->stack(1) as $node) { - pq($node) - ->contents()->toReference($content)->end() - ->replaceWith($markup->clone()->append($content)); - } - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function eq($num) { - $oldStack = $this->elements; - $this->elementsBackup = $this->elements; - $this->elements = array(); - if ( isset($oldStack[$num]) ) - $this->elements[] = $oldStack[$num]; - return $this->newInstance(); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function size() { - return count($this->elements); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @deprecated Use length as attribute - */ - public function length() { - return $this->size(); - } - public function count() { - return $this->size(); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo $level - */ - public function end($level = 1) { -// $this->elements = array_pop( $this->history ); -// return $this; -// $this->previous->DOM = $this->DOM; -// $this->previous->XPath = $this->XPath; - return $this->previous - ? $this->previous - : $this; - } - /** - * Enter description here... - * Normal use ->clone() . - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @access private - */ - public function _clone() { - $newStack = array(); - //pr(array('copy... ', $this->whois())); - //$this->dumpHistory('copy'); - $this->elementsBackup = $this->elements; - foreach($this->elements as $node) { - $newStack[] = $node->cloneNode(true); - } - $this->elements = $newStack; - return $this->newInstance(); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function replaceWithPHP($code) { - return $this->replaceWith(phpQuery::php($code)); - } - /** - * Enter description here... - * - * @param String|phpQuery $content - * @link http://docs.jquery.com/Manipulation/replaceWith#content - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function replaceWith($content) { - return $this->after($content)->remove(); - } - /** - * Enter description here... - * - * @param String $selector - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo this works ? - */ - public function replaceAll($selector) { - foreach(phpQuery::pq($selector, $this->getDocumentID()) as $node) - phpQuery::pq($node, $this->getDocumentID()) - ->after($this->_clone()) - ->remove(); - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function remove($selector = null) { - $loop = $selector - ? $this->filter($selector)->elements - : $this->elements; - foreach($loop as $node) { - if (! $node->parentNode ) - continue; - if (isset($node->tagName)) - $this->debug("Removing '{$node->tagName}'"); - $node->parentNode->removeChild($node); - // Mutation event - $event = new DOMEvent(array( - 'target' => $node, - 'type' => 'DOMNodeRemoved' - )); - phpQueryEvents::trigger($this->getDocumentID(), - $event->type, array($event), $node - ); - } - return $this; - } - protected function markupEvents($newMarkup, $oldMarkup, $node) { - if ($node->tagName == 'textarea' && $newMarkup != $oldMarkup) { - $event = new DOMEvent(array( - 'target' => $node, - 'type' => 'change' - )); - phpQueryEvents::trigger($this->getDocumentID(), - $event->type, array($event), $node - ); - } - } - /** - * jQuey difference - * - * @param $markup - * @return unknown_type - * @TODO trigger change event for textarea - */ - public function markup($markup = null, $callback1 = null, $callback2 = null, $callback3 = null) { - $args = func_get_args(); - if ($this->documentWrapper->isXML) - return call_user_func_array(array($this, 'xml'), $args); - else - return call_user_func_array(array($this, 'html'), $args); - } - /** - * jQuey difference - * - * @param $markup - * @return unknown_type - */ - public function markupOuter($callback1 = null, $callback2 = null, $callback3 = null) { - $args = func_get_args(); - if ($this->documentWrapper->isXML) - return call_user_func_array(array($this, 'xmlOuter'), $args); - else - return call_user_func_array(array($this, 'htmlOuter'), $args); - } - /** - * Enter description here... - * - * @param unknown_type $html - * @return string|phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @TODO force html result - */ - public function html($html = null, $callback1 = null, $callback2 = null, $callback3 = null) { - if (isset($html)) { - // INSERT - $nodes = $this->documentWrapper->import($html); - $this->empty(); - foreach($this->stack(1) as $alreadyAdded => $node) { - // for now, limit events for textarea - if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea') - $oldHtml = pq($node, $this->getDocumentID())->markup(); - foreach($nodes as $newNode) { - $node->appendChild($alreadyAdded - ? $newNode->cloneNode(true) - : $newNode - ); - } - // for now, limit events for textarea - if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea') - $this->markupEvents($html, $oldHtml, $node); - } - return $this; - } else { - // FETCH - $return = $this->documentWrapper->markup($this->elements, true); - $args = func_get_args(); - foreach(array_slice($args, 1) as $callback) { - $return = phpQuery::callbackRun($callback, array($return)); - } - return $return; - } - } - /** - * @TODO force xml result - */ - public function xml($xml = null, $callback1 = null, $callback2 = null, $callback3 = null) { - $args = func_get_args(); - return call_user_func_array(array($this, 'html'), $args); - } - /** - * Enter description here... - * @TODO force html result - * - * @return String - */ - public function htmlOuter($callback1 = null, $callback2 = null, $callback3 = null) { - $markup = $this->documentWrapper->markup($this->elements); - // pass thou callbacks - $args = func_get_args(); - foreach($args as $callback) { - $markup = phpQuery::callbackRun($callback, array($markup)); - } - return $markup; - } - /** - * @TODO force xml result - */ - public function xmlOuter($callback1 = null, $callback2 = null, $callback3 = null) { - $args = func_get_args(); - return call_user_func_array(array($this, 'htmlOuter'), $args); - } - public function __toString() { - return $this->markupOuter(); - } - /** - * Just like html(), but returns markup with VALID (dangerous) PHP tags. - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo support returning markup with PHP tags when called without param - */ - public function php($code = null) { - return $this->markupPHP($code); - } - /** - * Enter description here... - * - * @param $code - * @return unknown_type - */ - public function markupPHP($code = null) { - return isset($code) - ? $this->markup(phpQuery::php($code)) - : phpQuery::markupToPHP($this->markup()); - } - /** - * Enter description here... - * - * @param $code - * @return unknown_type - */ - public function markupOuterPHP() { - return phpQuery::markupToPHP($this->markupOuter()); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function children($selector = null) { - $stack = array(); - foreach($this->stack(1) as $node) { -// foreach($node->getElementsByTagName('*') as $newNode) { - foreach($node->childNodes as $newNode) { - if ($newNode->nodeType != 1) - continue; - if ($selector && ! $this->is($selector, $newNode)) - continue; - if ($this->elementsContainsNode($newNode, $stack)) - continue; - $stack[] = $newNode; - } - } - $this->elementsBackup = $this->elements; - $this->elements = $stack; - return $this->newInstance(); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function ancestors($selector = null) { - return $this->children( $selector ); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function append( $content) { - return $this->insert($content, __FUNCTION__); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function appendPHP( $content) { - return $this->insert("", 'append'); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function appendTo( $seletor) { - return $this->insert($seletor, __FUNCTION__); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function prepend( $content) { - return $this->insert($content, __FUNCTION__); - } - /** - * Enter description here... - * - * @todo accept many arguments, which are joined, arrays maybe also - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function prependPHP( $content) { - return $this->insert("", 'prepend'); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function prependTo( $seletor) { - return $this->insert($seletor, __FUNCTION__); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function before($content) { - return $this->insert($content, __FUNCTION__); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function beforePHP( $content) { - return $this->insert("", 'before'); - } - /** - * Enter description here... - * - * @param String|phpQuery - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function insertBefore( $seletor) { - return $this->insert($seletor, __FUNCTION__); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function after( $content) { - return $this->insert($content, __FUNCTION__); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function afterPHP( $content) { - return $this->insert("", 'after'); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function insertAfter( $seletor) { - return $this->insert($seletor, __FUNCTION__); - } - /** - * Internal insert method. Don't use it. - * - * @param unknown_type $target - * @param unknown_type $type - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @access private - */ - public function insert($target, $type) { - $this->debug("Inserting data with '{$type}'"); - $to = false; - switch( $type) { - case 'appendTo': - case 'prependTo': - case 'insertBefore': - case 'insertAfter': - $to = true; - } - switch(gettype($target)) { - case 'string': - $insertFrom = $insertTo = array(); - if ($to) { - // INSERT TO - $insertFrom = $this->elements; - if (phpQuery::isMarkup($target)) { - // $target is new markup, import it - $insertTo = $this->documentWrapper->import($target); - // insert into selected element - } else { - // $tagret is a selector - $thisStack = $this->elements; - $this->toRoot(); - $insertTo = $this->find($target)->elements; - $this->elements = $thisStack; - } - } else { - // INSERT FROM - $insertTo = $this->elements; - $insertFrom = $this->documentWrapper->import($target); - } - break; - case 'object': - $insertFrom = $insertTo = array(); - // phpQuery - if ($target instanceof self) { - if ($to) { - $insertTo = $target->elements; - if ($this->documentFragment && $this->stackIsRoot()) - // get all body children -// $loop = $this->find('body > *')->elements; - // TODO test it, test it hard... -// $loop = $this->newInstance($this->root)->find('> *')->elements; - $loop = $this->root->childNodes; - else - $loop = $this->elements; - // import nodes if needed - $insertFrom = $this->getDocumentID() == $target->getDocumentID() - ? $loop - : $target->documentWrapper->import($loop); - } else { - $insertTo = $this->elements; - if ( $target->documentFragment && $target->stackIsRoot() ) - // get all body children -// $loop = $target->find('body > *')->elements; - $loop = $target->root->childNodes; - else - $loop = $target->elements; - // import nodes if needed - $insertFrom = $this->getDocumentID() == $target->getDocumentID() - ? $loop - : $this->documentWrapper->import($loop); - } - // DOMNODE - } elseif ($target instanceof DOMNODE) { - // import node if needed -// if ( $target->ownerDocument != $this->DOM ) -// $target = $this->DOM->importNode($target, true); - if ( $to) { - $insertTo = array($target); - if ($this->documentFragment && $this->stackIsRoot()) - // get all body children - $loop = $this->root->childNodes; -// $loop = $this->find('body > *')->elements; - else - $loop = $this->elements; - foreach($loop as $fromNode) - // import nodes if needed - $insertFrom[] = ! $fromNode->ownerDocument->isSameNode($target->ownerDocument) - ? $target->ownerDocument->importNode($fromNode, true) - : $fromNode; - } else { - // import node if needed - if (! $target->ownerDocument->isSameNode($this->document)) - $target = $this->document->importNode($target, true); - $insertTo = $this->elements; - $insertFrom[] = $target; - } - } - break; - } - phpQuery::debug("From ".count($insertFrom)."; To ".count($insertTo)." nodes"); - foreach($insertTo as $insertNumber => $toNode) { - // we need static relative elements in some cases - switch( $type) { - case 'prependTo': - case 'prepend': - $firstChild = $toNode->firstChild; - break; - case 'insertAfter': - case 'after': - $nextSibling = $toNode->nextSibling; - break; - } - foreach($insertFrom as $fromNode) { - // clone if inserted already before - $insert = $insertNumber - ? $fromNode->cloneNode(true) - : $fromNode; - switch($type) { - case 'appendTo': - case 'append': -// $toNode->insertBefore( -// $fromNode, -// $toNode->lastChild->nextSibling -// ); - $toNode->appendChild($insert); - $eventTarget = $insert; - break; - case 'prependTo': - case 'prepend': - $toNode->insertBefore( - $insert, - $firstChild - ); - break; - case 'insertBefore': - case 'before': - if (! $toNode->parentNode) - throw new Exception("No parentNode, can't do {$type}()"); - else - $toNode->parentNode->insertBefore( - $insert, - $toNode - ); - break; - case 'insertAfter': - case 'after': - if (! $toNode->parentNode) - throw new Exception("No parentNode, can't do {$type}()"); - else - $toNode->parentNode->insertBefore( - $insert, - $nextSibling - ); - break; - } - // Mutation event - $event = new DOMEvent(array( - 'target' => $insert, - 'type' => 'DOMNodeInserted' - )); - phpQueryEvents::trigger($this->getDocumentID(), - $event->type, array($event), $insert - ); - } - } - return $this; - } - /** - * Enter description here... - * - * @return Int - */ - public function index($subject) { - $index = -1; - $subject = $subject instanceof phpQueryObject - ? $subject->elements[0] - : $subject; - foreach($this->newInstance() as $k => $node) { - if ($node->isSameNode($subject)) - $index = $k; - } - return $index; - } - /** - * Enter description here... - * - * @param unknown_type $start - * @param unknown_type $end - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @testme - */ - public function slice($start, $end = null) { -// $last = count($this->elements)-1; -// $end = $end -// ? min($end, $last) -// : $last; -// if ($start < 0) -// $start = $last+$start; -// if ($start > $last) -// return array(); - if ($end > 0) - $end = $end-$start; - return $this->newInstance( - array_slice($this->elements, $start, $end) - ); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function reverse() { - $this->elementsBackup = $this->elements; - $this->elements = array_reverse($this->elements); - return $this->newInstance(); - } - /** - * Return joined text content. - * @return String - */ - public function text($text = null, $callback1 = null, $callback2 = null, $callback3 = null) { - if (isset($text)) - return $this->html(htmlspecialchars($text)); - $args = func_get_args(); - $args = array_slice($args, 1); - $return = ''; - foreach($this->elements as $node) { - $text = $node->textContent; - if (count($this->elements) > 1 && $text) - $text .= "\n"; - foreach($args as $callback) { - $text = phpQuery::callbackRun($callback, array($text)); - } - $return .= $text; - } - return $return; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function plugin($class, $file = null) { - phpQuery::plugin($class, $file); - return $this; - } - /** - * Deprecated, use $pq->plugin() instead. - * - * @deprecated - * @param $class - * @param $file - * @return unknown_type - */ - public static function extend($class, $file = null) { - return $this->plugin($class, $file); - } - /** - * - * @access private - * @param $method - * @param $args - * @return unknown_type - */ - public function __call($method, $args) { - $aliasMethods = array('clone', 'empty'); - if (isset(phpQuery::$extendMethods[$method])) { - array_unshift($args, $this); - return phpQuery::callbackRun( - phpQuery::$extendMethods[$method], $args - ); - } else if (isset(phpQuery::$pluginsMethods[$method])) { - array_unshift($args, $this); - $class = phpQuery::$pluginsMethods[$method]; - $realClass = "phpQueryObjectPlugin_$class"; - $return = call_user_func_array( - array($realClass, $method), - $args - ); - // XXX deprecate ? - return is_null($return) - ? $this - : $return; - } else if (in_array($method, $aliasMethods)) { - return call_user_func_array(array($this, '_'.$method), $args); - } else - throw new Exception("Method '{$method}' doesnt exist"); - } - /** - * Safe rename of next(). - * - * Use it ONLY when need to call next() on an iterated object (in same time). - * Normaly there is no need to do such thing ;) - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @access private - */ - public function _next($selector = null) { - return $this->newInstance( - $this->getElementSiblings('nextSibling', $selector, true) - ); - } - /** - * Use prev() and next(). - * - * @deprecated - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @access private - */ - public function _prev($selector = null) { - return $this->prev($selector); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function prev($selector = null) { - return $this->newInstance( - $this->getElementSiblings('previousSibling', $selector, true) - ); - } - /** - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo - */ - public function prevAll($selector = null) { - return $this->newInstance( - $this->getElementSiblings('previousSibling', $selector) - ); - } - /** - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo FIXME: returns source elements insted of next siblings - */ - public function nextAll($selector = null) { - return $this->newInstance( - $this->getElementSiblings('nextSibling', $selector) - ); - } - /** - * @access private - */ - protected function getElementSiblings($direction, $selector = null, $limitToOne = false) { - $stack = array(); - $count = 0; - foreach($this->stack() as $node) { - $test = $node; - while( isset($test->{$direction}) && $test->{$direction}) { - $test = $test->{$direction}; - if (! $test instanceof DOMELEMENT) - continue; - $stack[] = $test; - if ($limitToOne) - break; - } - } - if ($selector) { - $stackOld = $this->elements; - $this->elements = $stack; - $stack = $this->filter($selector, true)->stack(); - $this->elements = $stackOld; - } - return $stack; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function siblings($selector = null) { - $stack = array(); - $siblings = array_merge( - $this->getElementSiblings('previousSibling', $selector), - $this->getElementSiblings('nextSibling', $selector) - ); - foreach($siblings as $node) { - if (! $this->elementsContainsNode($node, $stack)) - $stack[] = $node; - } - return $this->newInstance($stack); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function not($selector = null) { - if (is_string($selector)) - phpQuery::debug(array('not', $selector)); - else - phpQuery::debug('not'); - $stack = array(); - if ($selector instanceof self || $selector instanceof DOMNODE) { - foreach($this->stack() as $node) { - if ($selector instanceof self) { - $matchFound = false; - foreach($selector->stack() as $notNode) { - if ($notNode->isSameNode($node)) - $matchFound = true; - } - if (! $matchFound) - $stack[] = $node; - } else if ($selector instanceof DOMNODE) { - if (! $selector->isSameNode($node)) - $stack[] = $node; - } else { - if (! $this->is($selector)) - $stack[] = $node; - } - } - } else { - $orgStack = $this->stack(); - $matched = $this->filter($selector, true)->stack(); -// $matched = array(); -// // simulate OR in filter() instead of AND 5y -// foreach($this->parseSelector($selector) as $s) { -// $matched = array_merge($matched, -// $this->filter(array($s))->stack() -// ); -// } - foreach($orgStack as $node) - if (! $this->elementsContainsNode($node, $matched)) - $stack[] = $node; - } - return $this->newInstance($stack); - } - /** - * Enter description here... - * - * @param string|phpQueryObject - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function add($selector = null) { - if (! $selector) - return $this; - $stack = array(); - $this->elementsBackup = $this->elements; - $found = phpQuery::pq($selector, $this->getDocumentID()); - $this->merge($found->elements); - return $this->newInstance(); - } - /** - * @access private - */ - protected function merge() { - foreach(func_get_args() as $nodes) - foreach($nodes as $newNode ) - if (! $this->elementsContainsNode($newNode) ) - $this->elements[] = $newNode; - } - /** - * @access private - * TODO refactor to stackContainsNode - */ - protected function elementsContainsNode($nodeToCheck, $elementsStack = null) { - $loop = ! is_null($elementsStack) - ? $elementsStack - : $this->elements; - foreach($loop as $node) { - if ( $node->isSameNode( $nodeToCheck ) ) - return true; - } - return false; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function parent($selector = null) { - $stack = array(); - foreach($this->elements as $node ) - if ( $node->parentNode && ! $this->elementsContainsNode($node->parentNode, $stack) ) - $stack[] = $node->parentNode; - $this->elementsBackup = $this->elements; - $this->elements = $stack; - if ( $selector ) - $this->filter($selector, true); - return $this->newInstance(); - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function parents($selector = null) { - $stack = array(); - if (! $this->elements ) - $this->debug('parents() - stack empty'); - foreach($this->elements as $node) { - $test = $node; - while( $test->parentNode) { - $test = $test->parentNode; - if ($this->isRoot($test)) - break; - if (! $this->elementsContainsNode($test, $stack)) { - $stack[] = $test; - continue; - } - } - } - $this->elementsBackup = $this->elements; - $this->elements = $stack; - if ( $selector ) - $this->filter($selector, true); - return $this->newInstance(); - } - /** - * Internal stack iterator. - * - * @access private - */ - public function stack($nodeTypes = null) { - if (!isset($nodeTypes)) - return $this->elements; - if (!is_array($nodeTypes)) - $nodeTypes = array($nodeTypes); - $return = array(); - foreach($this->elements as $node) { - if (in_array($node->nodeType, $nodeTypes)) - $return[] = $node; - } - return $return; - } - // TODO phpdoc; $oldAttr is result of hasAttribute, before any changes - protected function attrEvents($attr, $oldAttr, $oldValue, $node) { - // skip events for XML documents - if (! $this->isXHTML() && ! $this->isHTML()) - return; - $event = null; - // identify - $isInputValue = $node->tagName == 'input' - && ( - in_array($node->getAttribute('type'), - array('text', 'password', 'hidden')) - || !$node->getAttribute('type') - ); - $isRadio = $node->tagName == 'input' - && $node->getAttribute('type') == 'radio'; - $isCheckbox = $node->tagName == 'input' - && $node->getAttribute('type') == 'checkbox'; - $isOption = $node->tagName == 'option'; - if ($isInputValue && $attr == 'value' && $oldValue != $node->getAttribute($attr)) { - $event = new DOMEvent(array( - 'target' => $node, - 'type' => 'change' - )); - } else if (($isRadio || $isCheckbox) && $attr == 'checked' && ( - // check - (! $oldAttr && $node->hasAttribute($attr)) - // un-check - || (! $node->hasAttribute($attr) && $oldAttr) - )) { - $event = new DOMEvent(array( - 'target' => $node, - 'type' => 'change' - )); - } else if ($isOption && $node->parentNode && $attr == 'selected' && ( - // select - (! $oldAttr && $node->hasAttribute($attr)) - // un-select - || (! $node->hasAttribute($attr) && $oldAttr) - )) { - $event = new DOMEvent(array( - 'target' => $node->parentNode, - 'type' => 'change' - )); - } - if ($event) { - phpQueryEvents::trigger($this->getDocumentID(), - $event->type, array($event), $node - ); - } - } - public function attr($attr = null, $value = null) { - foreach($this->stack(1) as $node) { - if (! is_null($value)) { - $loop = $attr == '*' - ? $this->getNodeAttrs($node) - : array($attr); - foreach($loop as $a) { - $oldValue = $node->getAttribute($a); - $oldAttr = $node->hasAttribute($a); - // TODO raises an error when charset other than UTF-8 - // while document's charset is also not UTF-8 - @$node->setAttribute($a, $value); - $this->attrEvents($a, $oldAttr, $oldValue, $node); - } - } else if ($attr == '*') { - // jQuery difference - $return = array(); - foreach($node->attributes as $n => $v) - $return[$n] = $v->value; - return $return; - } else - return $node->hasAttribute($attr) - ? $node->getAttribute($attr) - : null; - } - return is_null($value) - ? '' : $this; - } - /** - * @access private - */ - protected function getNodeAttrs($node) { - $return = array(); - foreach($node->attributes as $n => $o) - $return[] = $n; - return $return; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo check CDATA ??? - */ - public function attrPHP($attr, $code) { - if (! is_null($code)) { - $value = '<'.'?php '.$code.' ?'.'>'; - // TODO tempolary solution - // http://code.google.com/p/phpquery/issues/detail?id=17 -// if (function_exists('mb_detect_encoding') && mb_detect_encoding($value) == 'ASCII') -// $value = mb_convert_encoding($value, 'UTF-8', 'HTML-ENTITIES'); - } - foreach($this->stack(1) as $node) { - if (! is_null($code)) { -// $attrNode = $this->DOM->createAttribute($attr); - $node->setAttribute($attr, $value); -// $attrNode->value = $value; -// $node->appendChild($attrNode); - } else if ( $attr == '*') { - // jQuery diff - $return = array(); - foreach($node->attributes as $n => $v) - $return[$n] = $v->value; - return $return; - } else - return $node->getAttribute($attr); - } - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function removeAttr($attr) { - foreach($this->stack(1) as $node) { - $loop = $attr == '*' - ? $this->getNodeAttrs($node) - : array($attr); - foreach($loop as $a) { - $oldValue = $node->getAttribute($a); - $node->removeAttribute($a); - $this->attrEvents($a, $oldValue, null, $node); - } - } - return $this; - } - /** - * Return form element value. - * - * @return String Fields value. - */ - public function val($val = null) { - if (! isset($val)) { - if ($this->eq(0)->is('select')) { - $selected = $this->eq(0)->find('option[selected=selected]'); - if ($selected->is('[value]')) - return $selected->attr('value'); - else - return $selected->text(); - } else if ($this->eq(0)->is('textarea')) - return $this->eq(0)->markup(); - else - return $this->eq(0)->attr('value'); - } else { - $_val = null; - foreach($this->stack(1) as $node) { - $node = pq($node, $this->getDocumentID()); - if (is_array($val) && in_array($node->attr('type'), array('checkbox', 'radio'))) { - $isChecked = in_array($node->attr('value'), $val) - || in_array($node->attr('name'), $val); - if ($isChecked) - $node->attr('checked', 'checked'); - else - $node->removeAttr('checked'); - } else if ($node->get(0)->tagName == 'select') { - if (! isset($_val)) { - $_val = array(); - if (! is_array($val)) - $_val = array((string)$val); - else - foreach($val as $v) - $_val[] = $v; - } - foreach($node['option']->stack(1) as $option) { - $option = pq($option, $this->getDocumentID()); - $selected = false; - // XXX: workaround for string comparsion, see issue #96 - // http://code.google.com/p/phpquery/issues/detail?id=96 - $selected = is_null($option->attr('value')) - ? in_array($option->markup(), $_val) - : in_array($option->attr('value'), $_val); -// $optionValue = $option->attr('value'); -// $optionText = $option->text(); -// $optionTextLenght = mb_strlen($optionText); -// foreach($_val as $v) -// if ($optionValue == $v) -// $selected = true; -// else if ($optionText == $v && $optionTextLenght == mb_strlen($v)) -// $selected = true; - if ($selected) - $option->attr('selected', 'selected'); - else - $option->removeAttr('selected'); - } - } else if ($node->get(0)->tagName == 'textarea') - $node->markup($val); - else - $node->attr('value', $val); - } - } - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function andSelf() { - if ( $this->previous ) - $this->elements = array_merge($this->elements, $this->previous->elements); - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function addClass( $className) { - if (! $className) - return $this; - foreach($this->stack(1) as $node) { - if (! $this->is(".$className", $node)) - $node->setAttribute( - 'class', - trim($node->getAttribute('class').' '.$className) - ); - } - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function addClassPHP( $className) { - foreach($this->stack(1) as $node) { - $classes = $node->getAttribute('class'); - $newValue = $classes - ? $classes.' <'.'?php '.$className.' ?'.'>' - : '<'.'?php '.$className.' ?'.'>'; - $node->setAttribute('class', $newValue); - } - return $this; - } - /** - * Enter description here... - * - * @param string $className - * @return bool - */ - public function hasClass($className) { - foreach($this->stack(1) as $node) { - if ( $this->is(".$className", $node)) - return true; - } - return false; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function removeClass($className) { - foreach($this->stack(1) as $node) { - $classes = explode( ' ', $node->getAttribute('class')); - if ( in_array($className, $classes)) { - $classes = array_diff($classes, array($className)); - if ( $classes ) - $node->setAttribute('class', implode(' ', $classes)); - else - $node->removeAttribute('class'); - } - } - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function toggleClass($className) { - foreach($this->stack(1) as $node) { - if ( $this->is( $node, '.'.$className )) - $this->removeClass($className); - else - $this->addClass($className); - } - return $this; - } - /** - * Proper name without underscore (just ->empty()) also works. - * - * Removes all child nodes from the set of matched elements. - * - * Example: - * pq("p")._empty() - * - * HTML: - *

Hello, Person and person

- * - * Result: - * [

] - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @access private - */ - public function _empty() { - foreach($this->stack(1) as $node) { - // thx to 'dave at dgx dot cz' - $node->nodeValue = ''; - } - return $this; - } - /** - * Enter description here... - * - * @param array|string $callback Expects $node as first param, $index as second - * @param array $scope External variables passed to callback. Use compact('varName1', 'varName2'...) and extract($scope) - * @param array $arg1 Will ba passed as third and futher args to callback. - * @param array $arg2 Will ba passed as fourth and futher args to callback, and so on... - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function each($callback, $param1 = null, $param2 = null, $param3 = null) { - $paramStructure = null; - if (func_num_args() > 1) { - $paramStructure = func_get_args(); - $paramStructure = array_slice($paramStructure, 1); - } - foreach($this->elements as $v) - phpQuery::callbackRun($callback, array($v), $paramStructure); - return $this; - } - /** - * Run callback on actual object. - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function callback($callback, $param1 = null, $param2 = null, $param3 = null) { - $params = func_get_args(); - $params[0] = $this; - phpQuery::callbackRun($callback, $params); - return $this; - } - /** - * Enter description here... - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * @todo add $scope and $args as in each() ??? - */ - public function map($callback, $param1 = null, $param2 = null, $param3 = null) { -// $stack = array(); -//// foreach($this->newInstance() as $node) { -// foreach($this->newInstance() as $node) { -// $result = call_user_func($callback, $node); -// if ($result) -// $stack[] = $result; -// } - $params = func_get_args(); - array_unshift($params, $this->elements); - return $this->newInstance( - call_user_func_array(array('phpQuery', 'map'), $params) -// phpQuery::map($this->elements, $callback) - ); - } - /** - * Enter description here... - * - * @param $key - * @param $value - */ - public function data($key, $value = null) { - if (! isset($value)) { - // TODO? implement specific jQuery behavior od returning parent values - // is child which we look up doesn't exist - return phpQuery::data($this->get(0), $key, $value, $this->getDocumentID()); - } else { - foreach($this as $node) - phpQuery::data($node, $key, $value, $this->getDocumentID()); - return $this; - } - } - /** - * Enter description here... - * - * @param $key - */ - public function removeData($key) { - foreach($this as $node) - phpQuery::removeData($node, $key, $this->getDocumentID()); - return $this; - } - // INTERFACE IMPLEMENTATIONS - - // ITERATOR INTERFACE - /** - * @access private - */ - public function rewind(){ - $this->debug('iterating foreach'); -// phpQuery::selectDocument($this->getDocumentID()); - $this->elementsBackup = $this->elements; - $this->elementsInterator = $this->elements; - $this->valid = isset( $this->elements[0] ) - ? 1 : 0; -// $this->elements = $this->valid -// ? array($this->elements[0]) -// : array(); - $this->current = 0; - } - /** - * @access private - */ - public function current(){ - return $this->elementsInterator[ $this->current ]; - } - /** - * @access private - */ - public function key(){ - return $this->current; - } - /** - * Double-function method. - * - * First: main iterator interface method. - * Second: Returning next sibling, alias for _next(). - * - * Proper functionality is choosed automagicaly. - * - * @see phpQueryObject::_next() - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - */ - public function next($cssSelector = null){ -// if ($cssSelector || $this->valid) -// return $this->_next($cssSelector); - $this->valid = isset( $this->elementsInterator[ $this->current+1 ] ) - ? true - : false; - if (! $this->valid && $this->elementsInterator) { - $this->elementsInterator = null; - } else if ($this->valid) { - $this->current++; - } else { - return $this->_next($cssSelector); - } - } - /** - * @access private - */ - public function valid(){ - return $this->valid; - } - // ITERATOR INTERFACE END - // ARRAYACCESS INTERFACE - /** - * @access private - */ - public function offsetExists($offset) { - return $this->find($offset)->size() > 0; - } - /** - * @access private - */ - public function offsetGet($offset) { - return $this->find($offset); - } - /** - * @access private - */ - public function offsetSet($offset, $value) { -// $this->find($offset)->replaceWith($value); - $this->find($offset)->html($value); - } - /** - * @access private - */ - public function offsetUnset($offset) { - // empty - throw new Exception("Can't do unset, use array interface only for calling queries and replacing HTML."); - } - // ARRAYACCESS INTERFACE END - /** - * Returns node's XPath. - * - * @param unknown_type $oneNode - * @return string - * @TODO use native getNodePath is avaible - * @access private - */ - protected function getNodeXpath($oneNode = null, $namespace = null) { - $return = array(); - $loop = $oneNode - ? array($oneNode) - : $this->elements; -// if ($namespace) -// $namespace .= ':'; - foreach($loop as $node) { - if ($node instanceof DOMDOCUMENT) { - $return[] = ''; - continue; - } - $xpath = array(); - while(! ($node instanceof DOMDOCUMENT)) { - $i = 1; - $sibling = $node; - while($sibling->previousSibling) { - $sibling = $sibling->previousSibling; - $isElement = $sibling instanceof DOMELEMENT; - if ($isElement && $sibling->tagName == $node->tagName) - $i++; - } - $xpath[] = $this->isXML() - ? "*[local-name()='{$node->tagName}'][{$i}]" - : "{$node->tagName}[{$i}]"; - $node = $node->parentNode; - } - $xpath = join('/', array_reverse($xpath)); - $return[] = '/'.$xpath; - } - return $oneNode - ? $return[0] - : $return; - } - // HELPERS - public function whois($oneNode = null) { - $return = array(); - $loop = $oneNode - ? array( $oneNode ) - : $this->elements; - foreach($loop as $node) { - if (isset($node->tagName)) { - $tag = in_array($node->tagName, array('php', 'js')) - ? strtoupper($node->tagName) - : $node->tagName; - $return[] = $tag - .($node->getAttribute('id') - ? '#'.$node->getAttribute('id'):'') - .($node->getAttribute('class') - ? '.'.join('.', split(' ', $node->getAttribute('class'))):'') - .($node->getAttribute('name') - ? '[name="'.$node->getAttribute('name').'"]':'') - .($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') === false - ? '[value="'.substr(str_replace("\n", '', $node->getAttribute('value')), 0, 15).'"]':'') - .($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') !== false - ? '[value=PHP]':'') - .($node->getAttribute('selected') - ? '[selected]':'') - .($node->getAttribute('checked') - ? '[checked]':'') - ; - } else if ($node instanceof DOMTEXT) { - if (trim($node->textContent)) - $return[] = 'Text:'.substr(str_replace("\n", ' ', $node->textContent), 0, 15); - } else { - - } - } - return $oneNode && isset($return[0]) - ? $return[0] - : $return; - } - /** - * Dump htmlOuter and preserve chain. Usefull for debugging. - * - * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery - * - */ - public function dump() { - print 'DUMP #'.(phpQuery::$dumpCount++).' '; - $debug = phpQuery::$debug; - phpQuery::$debug = false; -// print __FILE__.':'.__LINE__."\n"; - var_dump($this->htmlOuter()); - return $this; - } - public function dumpWhois() { - print 'DUMP #'.(phpQuery::$dumpCount++).' '; - $debug = phpQuery::$debug; - phpQuery::$debug = false; -// print __FILE__.':'.__LINE__."\n"; - var_dump('whois', $this->whois()); - phpQuery::$debug = $debug; - return $this; - } - public function dumpLength() { - print 'DUMP #'.(phpQuery::$dumpCount++).' '; - $debug = phpQuery::$debug; - phpQuery::$debug = false; -// print __FILE__.':'.__LINE__."\n"; - var_dump('length', $this->length()); - phpQuery::$debug = $debug; - return $this; - } - public function dumpTree($html = true, $title = true) { - $output = $title - ? 'DUMP #'.(phpQuery::$dumpCount++)." \n" : ''; - $debug = phpQuery::$debug; - phpQuery::$debug = false; - foreach($this->stack() as $node) - $output .= $this->__dumpTree($node); - phpQuery::$debug = $debug; - print $html - ? nl2br(str_replace(' ', ' ', $output)) - : $output; - return $this; - } - private function __dumpTree($node, $intend = 0) { - $whois = $this->whois($node); - $return = ''; - if ($whois) - $return .= str_repeat(' - ', $intend).$whois."\n"; - if (isset($node->childNodes)) - foreach($node->childNodes as $chNode) - $return .= $this->__dumpTree($chNode, $intend+1); - return $return; - } - /** - * Dump htmlOuter and stop script execution. Usefull for debugging. - * - */ - public function dumpDie() { - print __FILE__.':'.__LINE__; - var_dump($this->htmlOuter()); - die(); - } -} diff --git a/phpQuery/phpQuery/plugins/Scripts.php b/phpQuery/phpQuery/plugins/Scripts.php deleted file mode 100644 index cc4dd6f..0000000 --- a/phpQuery/phpQuery/plugins/Scripts.php +++ /dev/null @@ -1,72 +0,0 @@ - \ No newline at end of file diff --git a/phpQuery/phpQuery/plugins/Scripts/__config.example.php b/phpQuery/phpQuery/plugins/Scripts/__config.example.php deleted file mode 100644 index db80652..0000000 --- a/phpQuery/phpQuery/plugins/Scripts/__config.example.php +++ /dev/null @@ -1,10 +0,0 @@ - array('login@mail', 'password'), -); -?> \ No newline at end of file diff --git a/phpQuery/phpQuery/plugins/Scripts/example.php b/phpQuery/phpQuery/plugins/Scripts/example.php deleted file mode 100644 index a8f45f4..0000000 --- a/phpQuery/phpQuery/plugins/Scripts/example.php +++ /dev/null @@ -1,14 +0,0 @@ -find($params[0]); -?> \ No newline at end of file diff --git a/phpQuery/phpQuery/plugins/Scripts/fix_webroot.php b/phpQuery/phpQuery/plugins/Scripts/fix_webroot.php deleted file mode 100644 index a7cac9e..0000000 --- a/phpQuery/phpQuery/plugins/Scripts/fix_webroot.php +++ /dev/null @@ -1,16 +0,0 @@ -filter($filter) as $el) { - $el = pq($el, $self->getDocumentID()); - // imgs and scripts - if ( $el->is('img') || $el->is('script') ) - $el->attr('src', $params[0].$el->attr('src')); - // css - if ( $el->is('link') ) - $el->attr('href', $params[0].$el->attr('href')); -} \ No newline at end of file diff --git a/phpQuery/phpQuery/plugins/Scripts/google_login.php b/phpQuery/phpQuery/plugins/Scripts/google_login.php deleted file mode 100644 index 0327045..0000000 --- a/phpQuery/phpQuery/plugins/Scripts/google_login.php +++ /dev/null @@ -1,47 +0,0 @@ - - */ -phpQuery::ajaxAllowHost( - 'code.google.com', - 'google.com', 'www.google.com', - 'mail.google.com', - 'docs.google.com', - 'reader.google.com' -); -if (! function_exists('ndfasui8923')) { - function ndfasui8923($browser, $scope) { - extract($scope); - $browser - ->WebBrowser() - ->find('#Email') - ->val($config['google_login'][0])->end() - ->find('#Passwd') - ->val($config['google_login'][1]) - ->parents('form') - ->submit(); - } - $ndfasui8923 = new Callback('ndfasui8923', new CallbackParam, compact( - 'config', 'self', 'return', 'params' - )); -} -phpQuery::plugin('WebBrowser'); -$self->document->xhr = phpQuery::$plugins->browserGet( - 'https://www.google.com/accounts/Login', - $ndfasui8923 -); -//$self->document->xhr = phpQuery::$plugins->browserGet('https://www.google.com/accounts/Login', create_function('$browser', " -// \$browser -// ->WebBrowser() -// ->find('#Email') -// ->val('{$config['google_login'][0]}')->end() -// ->find('#Passwd') -// ->val('".str_replace("'", "\\'", $config['google_login'][1])."') -// ->parents('form') -// ->submit();" -//)); -?> \ No newline at end of file diff --git a/phpQuery/phpQuery/plugins/Scripts/print_source.php b/phpQuery/phpQuery/plugins/Scripts/print_source.php deleted file mode 100644 index 03d8061..0000000 --- a/phpQuery/phpQuery/plugins/Scripts/print_source.php +++ /dev/null @@ -1,9 +0,0 @@ - - */ -/** @var phpQueryObject */ -$self = $self; -$return = htmlspecialchars($self); \ No newline at end of file diff --git a/phpQuery/phpQuery/plugins/Scripts/print_websafe.php b/phpQuery/phpQuery/plugins/Scripts/print_websafe.php deleted file mode 100644 index 4f48bd7..0000000 --- a/phpQuery/phpQuery/plugins/Scripts/print_websafe.php +++ /dev/null @@ -1,13 +0,0 @@ - - */ -/** @var phpQueryObject */ -$self = $self; -$self - ->find('script') - ->add('meta[http-equiv=refresh]') - ->add('meta[http-equiv=Refresh]') - ->remove(); \ No newline at end of file diff --git a/phpQuery/phpQuery/plugins/WebBrowser.php b/phpQuery/phpQuery/plugins/WebBrowser.php deleted file mode 100644 index 6688d3f..0000000 --- a/phpQuery/phpQuery/plugins/WebBrowser.php +++ /dev/null @@ -1,405 +0,0 @@ -_clone()->toRoot(); - $location = $location - ? $location - // TODO use document.location - : $self->document->xhr->getUri(true); - // FIXME tmp - $self->document->WebBrowserCallback = $callback; - if (! $location) - throw new Exception('Location needed to activate WebBrowser plugin !'); - else { - $self->bind('click', array($location, $callback), array('phpQueryPlugin_WebBrowser', 'hadleClick')); - $self->bind('submit', array($location, $callback), array('phpQueryPlugin_WebBrowser', 'handleSubmit')); - } - } - public static function browser($self, $callback = null, $location = null) { - return $self->WebBrowser($callback, $location); - } - public static function downloadTo($self, $dir = null, $filename = null) { - $url = null; - if ($self->is('a[href]')) - $url = $self->attr('href'); - else if ($self->find('a')->length) - $url = $self->find('a')->attr('href'); - if ($url) { - $url = resolve_url($self->document->location, $url); - if (! $dir) - $dir = getcwd(); - // TODO resolv name from response headers - if (! $filename) { - $matches = null; - preg_match('@/([^/]+)$@', $url, $matches); - $filename = $matches[1]; - } - //print $url; - $path = rtrim($dir, '/').'/'.$filename; - phpQuery::debug("Requesting download of $url\n"); - // TODO use AJAX instead of file_get_contents - file_put_contents($path, file_get_contents($url)); - } - return $self; - } - /** - * Method changing browser location. - * Fires callback registered with WebBrowser(), if any. - * @param $self - * @param $url - * @return unknown_type - */ - public static function location($self, $url = null) { - // TODO if ! $url return actual location ??? - $xhr = isset($self->document->xhr) - ? $self->document->xhr - : null; - $xhr = phpQuery::ajax(array( - 'url' => $url, - ), $xhr); - $return = false; - if ($xhr->getLastResponse()->isSuccessful()) { - $return = phpQueryPlugin_WebBrowser::browserReceive($xhr); - if (isset($self->document->WebBrowserCallback)) - phpQuery::callbackRun( - $self->document->WebBrowserCallback, - array($return) - ); - } - return $return; - } -} -class phpQueryPlugin_WebBrowser { - /** - * - * @param $url - * @param $callback - * @param $param1 - * @param $param2 - * @param $param3 - * @return Zend_Http_Client - */ - public static function browserGet($url, $callback, - $param1 = null, $param2 = null, $param3 = null) { - phpQuery::debug("[WebBrowser] GET: $url"); - self::authorizeHost($url); - $xhr = phpQuery::ajax(array( - 'type' => 'GET', - 'url' => $url, - 'dataType' => 'html', - )); - $paramStructure = null; - if (func_num_args() > 2) { - $paramStructure = func_get_args(); - $paramStructure = array_slice($paramStructure, 2); - } - if ($xhr->getLastResponse()->isSuccessful()) { - phpQuery::callbackRun($callback, - array(self::browserReceive($xhr)->WebBrowser()), - $paramStructure - ); -// phpQuery::callbackRun($callback, array( -// self::browserReceive($xhr)//->WebBrowser($callback) -// )); - return $xhr; - } else { - throw new Exception("[WebBrowser] GET request failed; url: $url"); - return false; - } - } - /** - * - * @param $url - * @param $data - * @param $callback - * @param $param1 - * @param $param2 - * @param $param3 - * @return Zend_Http_Client - */ - public static function browserPost($url, $data, $callback, - $param1 = null, $param2 = null, $param3 = null) { - self::authorizeHost($url); - $xhr = phpQuery::ajax(array( - 'type' => 'POST', - 'url' => $url, - 'dataType' => 'html', - 'data' => $data, - )); - $paramStructure = null; - if (func_num_args() > 3) { - $paramStructure = func_get_args(); - $paramStructure = array_slice($paramStructure, 3); - } - if ($xhr->getLastResponse()->isSuccessful()) { - phpQuery::callbackRun($callback, - array(self::browserReceive($xhr)->WebBrowser()), - $paramStructure - ); -// phpQuery::callbackRun($callback, array( -// self::browserReceive($xhr)//->WebBrowser($callback) -// )); - return $xhr; - } else - return false; - } - /** - * - * @param $ajaxSettings - * @param $callback - * @param $param1 - * @param $param2 - * @param $param3 - * @return Zend_Http_Client - */ - public static function browser($ajaxSettings, $callback, - $param1 = null, $param2 = null, $param3 = null) { - self::authorizeHost($ajaxSettings['url']); - $xhr = phpQuery::ajax( - self::ajaxSettingsPrepare($ajaxSettings) - ); - $paramStructure = null; - if (func_num_args() > 2) { - $paramStructure = func_get_args(); - $paramStructure = array_slice($paramStructure, 2); - } - if ($xhr->getLastResponse()->isSuccessful()) { - phpQuery::callbackRun($callback, - array(self::browserReceive($xhr)->WebBrowser()), - $paramStructure - ); -// phpQuery::callbackRun($callback, array( -// self::browserReceive($xhr)//->WebBrowser($callback) -// )); - return $xhr; - } else - return false; - } - protected static function authorizeHost($url) { - $host = parse_url($url, PHP_URL_HOST); - if ($host) - phpQuery::ajaxAllowHost($host); - } - protected static function ajaxSettingsPrepare($settings) { - unset($settings['success']); - unset($settings['error']); - return $settings; - } - /** - * @param Zend_Http_Client $xhr - */ - public static function browserReceive($xhr) { - phpQuery::debug("[WebBrowser] Received from ".$xhr->getUri(true)); - // TODO handle meta redirects - $body = $xhr->getLastResponse()->getBody(); - - // XXX error ??? - if (strpos($body, '') !== false) { - $body = '' - .str_replace('', '', $body) - .''; - } - $pq = phpQuery::newDocument($body); - $pq->document->xhr = $xhr; - $pq->document->location = $xhr->getUri(true); - $refresh = $pq->find('meta[http-equiv=refresh]') - ->add('meta[http-equiv=Refresh]'); - if ($refresh->size()) { -// print htmlspecialchars(var_export($xhr->getCookieJar()->getAllCookies(), true)); -// print htmlspecialchars(var_export($xhr->getLastResponse()->getHeader('Set-Cookie'), true)); - phpQuery::debug("Meta redirect... '{$refresh->attr('content')}'\n"); - // there is a refresh, so get the new url - $content = $refresh->attr('content'); - $urlRefresh = substr($content, strpos($content, '=')+1); - $urlRefresh = trim($urlRefresh, '\'"'); - // XXX not secure ?! - phpQuery::ajaxAllowURL($urlRefresh); -// $urlRefresh = urldecode($urlRefresh); - // make ajax call, passing last $xhr object to preserve important stuff - $xhr = phpQuery::ajax(array( - 'type' => 'GET', - 'url' => $urlRefresh, - 'dataType' => 'html', - ), $xhr); - if ($xhr->getLastResponse()->isSuccessful()) { - // if all is ok, repeat this method... - return call_user_func_array( - array('phpQueryPlugin_WebBrowser', 'browserReceive'), array($xhr) - ); - } - } else - return $pq; - } - /** - * - * @param $e - * @param $callback - * @return unknown_type - */ - public static function hadleClick($e, $callback = null) { - $node = phpQuery::pq($e->target); - $type = null; - if ($node->is('a[href]')) { - // TODO document.location - $xhr = isset($node->document->xhr) - ? $node->document->xhr - : null; - $xhr = phpQuery::ajax(array( - 'url' => resolve_url($e->data[0], $node->attr('href')), - 'referer' => $node->document->location, - ), $xhr); - if ((! $callback || !($callback instanceof Callback)) && $e->data[1]) - $callback = $e->data[1]; - if ($xhr->getLastResponse()->isSuccessful() && $callback) - phpQuery::callbackRun($callback, array( - self::browserReceive($xhr) - )); - } else if ($node->is(':submit') && $node->parents('form')->size()) - $node->parents('form')->trigger('submit', array($e)); - } - /** - * Enter description here... - * - * @param unknown_type $e - * @TODO trigger submit for form after form's submit button has a click event - */ - public static function handleSubmit($e, $callback = null) { - $node = phpQuery::pq($e->target); - if (!$node->is('form') || !$node->is('[action]')) - return; - // TODO document.location - $xhr = isset($node->document->xhr) - ? $node->document->xhr - : null; - $submit = pq($e->relatedTarget)->is(':submit') - ? $e->relatedTarget - // will this work ? -// : $node->find(':submit:first')->get(0); - : $node->find('*:submit:first')->get(0); - $data = array(); - foreach($node->serializeArray($submit) as $r) - // XXXt.c maybe $node->not(':submit')->add($sumit) would be better ? -// foreach($node->serializeArray($submit) as $r) - $data[ $r['name'] ] = $r['value']; - $options = array( - 'type' => $node->attr('method') - ? $node->attr('method') - : 'GET', - 'url' => resolve_url($e->data[0], $node->attr('action')), - 'data' => $data, - 'referer' => $node->document->location, -// 'success' => $e->data[1], - ); - if ($node->attr('enctype')) - $options['contentType'] = $node->attr('enctype'); - $xhr = phpQuery::ajax($options, $xhr); - if ((! $callback || !($callback instanceof Callback)) && $e->data[1]) - $callback = $e->data[1]; - if ($xhr->getLastResponse()->isSuccessful() && $callback) - phpQuery::callbackRun($callback, array( - self::browserReceive($xhr) - )); - } -} -/** - * - * @param unknown_type $parsed - * @return unknown - * @link http://www.php.net/manual/en/function.parse-url.php - * @author stevenlewis at hotmail dot com - */ -function glue_url($parsed) - { - if (! is_array($parsed)) return false; - $uri = isset($parsed['scheme']) ? $parsed['scheme'].':'.((strtolower($parsed['scheme']) == 'mailto') ? '':'//'): ''; - $uri .= isset($parsed['user']) ? $parsed['user'].($parsed['pass']? ':'.$parsed['pass']:'').'@':''; - $uri .= isset($parsed['host']) ? $parsed['host'] : ''; - $uri .= isset($parsed['port']) ? ':'.$parsed['port'] : ''; - if(isset($parsed['path'])) - { - $uri .= (substr($parsed['path'],0,1) == '/')?$parsed['path']:'/'.$parsed['path']; - } - $uri .= isset($parsed['query']) ? '?'.$parsed['query'] : ''; - $uri .= isset($parsed['fragment']) ? '#'.$parsed['fragment'] : ''; - return $uri; - } -/** - * Enter description here... - * - * @param unknown_type $base - * @param unknown_type $url - * @return unknown - * @author adrian-php at sixfingeredman dot net - */ -function resolve_url($base, $url) { - if (!strlen($base)) return $url; - // Step 2 - if (!strlen($url)) return $base; - // Step 3 - if (preg_match('!^[a-z]+:!i', $url)) return $url; - $base = parse_url($base); - if ($url{0} == "#") { - // Step 2 (fragment) - $base['fragment'] = substr($url, 1); - return unparse_url($base); - } - unset($base['fragment']); - unset($base['query']); - if (substr($url, 0, 2) == "//") { - // Step 4 - return unparse_url(array( - 'scheme'=>$base['scheme'], - 'path'=>substr($url,2), - )); - } else if ($url{0} == "/") { - // Step 5 - $base['path'] = $url; - } else { - // Step 6 - $path = explode('/', $base['path']); - $url_path = explode('/', $url); - // Step 6a: drop file from base - array_pop($path); - // Step 6b, 6c, 6e: append url while removing "." and ".." from - // the directory portion - $end = array_pop($url_path); - foreach ($url_path as $segment) { - if ($segment == '.') { - // skip - } else if ($segment == '..' && $path && $path[sizeof($path)-1] != '..') { - array_pop($path); - } else { - $path[] = $segment; - } - } - // Step 6d, 6f: remove "." and ".." from file portion - if ($end == '.') { - $path[] = ''; - } else if ($end == '..' && $path && $path[sizeof($path)-1] != '..') { - $path[sizeof($path)-1] = ''; - } else { - $path[] = $end; - } - // Step 6h - $base['path'] = join('/', $path); - - } - // Step 7 - return glue_url($base); -} diff --git a/phpQuery/phpQuery/plugins/example.php b/phpQuery/phpQuery/plugins/example.php deleted file mode 100644 index 732f05c..0000000 --- a/phpQuery/phpQuery/plugins/example.php +++ /dev/null @@ -1,75 +0,0 @@ -plugin('example') - * pq('ul')->plugin('example', 'example.php') - * - * Plugin classes are never intialized, just method calls are forwarded - * in static way from phpQuery. - * - * Have fun writing plugins :) - */ - -/** - * phpQuery plugin class extending phpQuery object. - * Methods from this class are callable on every phpQuery object. - * - * Class name prefix 'phpQueryObjectPlugin_' must be preserved. - */ -abstract class phpQueryObjectPlugin_example { - /** - * Limit binded methods. - * - * null means all public. - * array means only specified ones. - * - * @var array|null - */ - public static $phpQueryMethods = null; - /** - * Enter description here... - * - * @param phpQueryObject $self - */ - public static function example($self, $arg1) { - // this method can be called on any phpQuery object, like this: - // pq('div')->example('$arg1 Value') - - // do something - $self->append('Im just an example !'); - // change stack of result object - return $self->find('div'); - } - protected static function helperFunction() { - // this method WONT be avaible as phpQuery method, - // because it isn't publicly callable - } -} - -/** - * phpQuery plugin class extending phpQuery static namespace. - * Methods from this class are callable as follows: - * phpQuery::$plugins->staticMethod() - * - * Class name prefix 'phpQueryPlugin_' must be preserved. - */ -abstract class phpQueryPlugin_example { - /** - * Limit binded methods. - * - * null means all public. - * array means only specified ones. - * - * @var array|null - */ - public static $phpQueryMethods = null; - public static function staticMethod() { - // this method can be called within phpQuery class namespace, like this: - // phpQuery::$plugins->staticMethod() - } -} -?> \ No newline at end of file