406 lines
12 KiB
PHP
406 lines
12 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* WebBrowser plugin.
|
||
|
*
|
||
|
*/
|
||
|
class phpQueryObjectPlugin_WebBrowser {
|
||
|
/**
|
||
|
* Limit binded methods to specified ones.
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
public static $phpQueryMethods = null;
|
||
|
/**
|
||
|
* Enter description here...
|
||
|
*
|
||
|
* @param phpQueryObject $self
|
||
|
* @todo support 'reset' event
|
||
|
*/
|
||
|
public static function WebBrowser($self, $callback = null, $location = null) {
|
||
|
$self = $self->_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, '<!doctype html>') !== false) {
|
||
|
$body = '<html>'
|
||
|
.str_replace('<!doctype html>', '', $body)
|
||
|
.'</html>';
|
||
|
}
|
||
|
$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);
|
||
|
}
|