static function php($string, $urlInterpolation = false) { $string = (string) $string; false !== strpos($string, '&') && ($string = str_replace(array(''', '"', '>', '<', '&'), array("'", '"', '>', '<', '&'), $string)); $urlInterpolation && false !== strpos($string, '{') && ($string = str_replace(array('{/}', '{~}'), array(Patchwork::__HOST__(), Patchwork::__BASE__()), $string)); return $string; }
function __construct($url) { $url = (string) $url; $url = '' === $url ? '' : (preg_match("'^([^:/]+:/|\\.+)?/'", $url) ? $url : p::__BASE__() . ('index' === $url ? '' : $url)); if ('.' === substr($url, 0, 1)) { user_error('Current redirection behaviour with relative URLs may change in a future version of Patchwork. As long as this notice appears, using relative URLs is strongly discouraged.'); } $this->url = $url; }
static function php($text, $url = '', $attributes = '') { $url = (string) $url; $a = strpos($url, '#'); if (false !== $a) { $hash = substr($url, $a); $url = substr($url, 0, $a); } else { $hash = ''; } return $url == htmlspecialchars(substr(Patchwork::__HOST__() . substr($_SERVER['REQUEST_URI'], 1), strlen(Patchwork::__BASE__()))) ? '<b class="linkloop">' . $text . '</b>' : '<a href="' . Patchwork::base($url, true) . $hash . '" ' . $attributes . '>' . $text . '</a>'; }
protected function doSchedule($time) { $db = $this->getPdoConnection(); if ($time < $_SERVER['REQUEST_TIME'] - 366 * 86400) { $time += $_SERVER['REQUEST_TIME']; } $data = array('task' => $this, 'cookie' => &$_COOKIE, 'session' => class_exists('SESSION', false) ? s::getAll() : array()); $sql = "INSERT INTO queue (base, data, run_time)\n VALUES (?,?,?)"; $db->prepare($sql)->execute(array(p::__BASE__(), serialize($data), $time)); $id = $db->lastInsertId(); $this->registerQueue(); return $id; }
function redirect($javascript) { p::disable(); $url = $this->url; $url = '' === $url ? '' : (preg_match("'^([^:/]+:/|\\.+)?/'", $url) ? $url : p::__BASE__() . ('index' === $url ? '' : $url)); if ($javascript) { $url = 'location.replace(' . ('' !== $url ? "'" . addslashes($url) . "'" : 'location') . ')'; header('Content-Length: ' . strlen($url)); echo $url; } else { header('HTTP/1.1 302 Found'); header('Location: ' . ('' !== $url ? $url : $_SERVER['REQUEST_URI'])); } }
static function resolve($agent) { static $cache = array(); if (isset($cache[$agent])) { return $cache[$agent]; } else { $cache[$agent] =& $trace; } $args = array(); $BASE = p::__BASE__(); $agent = rawurlencode($agent); $agent = str_replace(array('%21', '%7E', '%2A', '%28', '%29', '%2C', '%2F', '%3A', '%40', '%24', '%3B'), array('!', '~', '*', '(', ')', ',', '/', ':', '@', '$', ';'), $agent); $agent = p::base($agent, true); $agent = preg_replace("'^.*?://[^/]*'", '', $agent); $h = patchwork_http_socket($_SERVER['SERVER_ADDR'], $_SERVER['SERVER_PORT'], isset($_SERVER['HTTPS'])); $keys = p::$lang; $keys = "GET {$agent}?p:=k:{$keys} HTTP/1.0\r\n"; $keys .= "Host: {$_SERVER['HTTP_HOST']}\r\n"; $keys .= "Connection: close\r\n\r\n"; fwrite($h, $keys); $keys = array(); while (false !== ($a = fgets($h))) { $keys[] = $a; } fclose($h); $h = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; $h = "/w\\.k\\((-?[0-9]+),({$h}),({$h}),({$h}),\\[((?:{$h}(?:,{$h})*)?)\\]\\)/su"; if (!preg_match($h, implode('', $keys), $keys)) { user_error('Error while getting meta info data for ' . htmlspecialchars($agent)); p::disable(true); } $appId = (int) $keys[1]; $base = stripcslashes(substr($keys[2], 1, -1)); $agent = stripcslashes(substr($keys[3], 1, -1)); $a = stripcslashes(substr($keys[4], 1, -1)); $keys = eval('return array(' . $keys[5] . ');'); if ('' !== $a) { $args['__0__'] = $a; $i = 0; foreach (explode('/', $a) as $a) { $args['__' . ++$i . '__'] = $a; } } if ($base === $BASE) { $appId = $base = false; } else { p::watch('foreignTrace'); } return $trace = array($appId, $base, $agent, $keys, $args); }
protected function pushMail($mailer, &$headers, &$options) { if (isset($options['testMode'])) { $this->testMode = $options['testMode']; } else { if ($this->testMode) { $options['testMode'] = 1; } } $sent = -(int) (bool) (!empty($options['testMode'])); $archive = (int) (!(empty($options['archive']) && empty($options['testMode']))); $time = isset($options['time']) ? $options['time'] : 0; if ($time < $_SERVER['REQUEST_TIME'] - 366 * 86400) { $time += $_SERVER['REQUEST_TIME']; } if (!empty($options['attachments']) && is_array($options['attachments'])) { $tmpToken = false; foreach ($options['attachments'] as &$file) { if (is_uploaded_file($file) || PATCHWORK_ZCACHE === substr($file, 0, strlen(PATCHWORK_ZCACHE))) { $tmpToken || ($tmpToken = p::strongId(8)); $base = PATCHWORK_ZCACHE . p::strongId(8) . '~' . $tmpToken; copy($file, $base); $file = $base; } } unset($file, $options['attachments.tmpToken']); $tmpToken && ($options['attachments.tmpToken'] = $tmpToken); } $data = array('mailer' => $mailer, 'headers' => &$headers, 'options' => &$options, 'cookie' => &$_COOKIE, 'session' => class_exists('SESSION', false) ? s::getAll() : array()); $db = $this->getPdoConnection(); $sql = "INSERT INTO queue (base, data, send_time, archive, sent_time)\n VALUES (?,?,?,?,?)"; $db->prepare($sql)->execute(array(p::__BASE__(), serialize($data), $time, $archive, $sent)); $sql = $db->lastInsertId(); $this->registerQueue(); return $sql; }
function compose($o) { $o->DATA = '/*<script>/**/q="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $this->getJs($this->data)) . '"//</script>' . '<script src="' . Patchwork::__BASE__() . 'js/QJsrsHandler"></script>'; return $o; }
protected static function sendDebugInfo() { ob_start(function_exists('ob_gzhandler') ? 'ob_gzhandler' : null, 1 << 14); header('Content-Type: text/html; charset=utf-8'); header('Cache-Control: max-age=0,private,must-revalidate'); set_time_limit(0); ignore_user_abort(true); ?> <!doctype html> <html> <head> <title>Debug Window</title> <link type="text/css" rel="stylesheet" href="<?php echo p::__BASE__() . 'css/patchwork-console.css?' . $GLOBALS['patchwork_appId']; ?> "> </head> <body> <script src="<?php echo p::__BASE__() . 'js/patchwork-console.js?' . $GLOBALS['patchwork_appId']; ?> "></script> <div id="events" style="display:none"> <?php $handlers = array(); for (;;) { foreach (scandir(PATCHWORK_ZCACHE) as $log) { if ('.log' === substr($log = PATCHWORK_ZCACHE . $log, -4)) { if (rename($log, $log .= '~')) { ($h = fopen($log, 'rb')) ? $handlers[$log] = $h : unlink($log); } } } $count = 0; foreach ($handlers as $log => $h) { if (false === ($next_line = fgets($h))) { ++$count; } else { while (false !== ($line = $next_line)) { $next_line = fgets($h); self::parseLine($line, $next_line); for (;;) { if (false !== ($line = reset(self::$buffer))) { echo implode('', $line); if ($line && false === end($line)) { unset(self::$buffer[key(self::$buffer)]); ob_flush(); flush(); if (connection_aborted()) { break 4; } else { continue; } } else { self::$buffer[key(self::$buffer)] = array(); } } break; } } } } if ($count === count($handlers)) { break; } usleep(150000); } foreach ($handlers as $log => $h) { fclose($h) + unlink($log); } ?> </div> <script> scrollTo(0,0); var i, b = window.parent && parent.E && parent.E.buffer; for (i in b) patchworkConsole.log("client-dump", b[i]); parent.E.buffer = []; </script> <?php }
static function render($agent, $liveAgent) { $config_maxage = $CONFIG['maxage']; // Get the calling URI if (isset($_COOKIE['R$'])) { p::$uri = $_COOKIE['R$']; setcookie('R$', '', 1, '/'); // Check the Referer header // T$ starts with 2 when the Referer's confidence is unknown // 1 when it is trusted if (isset($_SERVER['HTTP_REFERER']) && $_COOKIE['R$'] === $_SERVER['HTTP_REFERER']) { if (class_exists('SESSION', false)) { $_COOKIE['T$'] = '1'; s::regenerateId(); } else { self::$antiCsrfToken[0] = '1'; setcookie('T$', self::$antiCsrfToken, 0, $CONFIG['session.cookie_path'], $CONFIG['session.cookie_domain']); } } } else { p::$uri = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : p::$base; } if ($liveAgent) { // The output is both html and js, but iframe transport layer needs html p::$binaryMode = true; header('Content-Type: text/html'); echo '/*<script>/**/q="'; } else { echo 'w('; } p::openMeta($agent); try { if (isset($_GET['T$']) && !p::$antiCsrfMatch) { throw new e\PrivateResource(); } $a = new $agent($_GET); $group = p::closeGroupStage(); if ($is_cacheable = 'POST' !== $_SERVER['REQUEST_METHOD'] && !in_array('private', $group)) { $cagent = p::agentCache($agent, $a->get, 'js.ser', $group); $dagent = p::getContextualCachePath('jsdata.' . $agent, 'js.ser', $cagent); if ($liveAgent) { if (file_exists($dagent)) { if (filemtime($dagent) > $_SERVER['REQUEST_TIME']) { $data = unserialize(file_get_contents($dagent)); p::setMaxage($data['maxage']); p::setExpires($data['expires']); p::writeWatchTable($data['watch']); array_map('header', $data['headers']); p::closeMeta(); echo str_replace(array('\\', '"', '</'), array('\\\\', '\\"', '<\\/'), $data['rawdata']), '"//</script><script src="' . p::__BASE__() . 'js/QJsrsHandler"></script>'; return; } else { @(unlink($cagent) + unlink($dagent)); } } } else { if (file_exists($cagent)) { if (filemtime($cagent) > $_SERVER['REQUEST_TIME']) { $data = unserialize(file_get_contents($cagent)); p::setMaxage($data['maxage']); p::setExpires($data['expires']); p::writeWatchTable($data['watch']); array_map('header', $data['headers']); p::closeMeta(); echo $data['rawdata']; return; } else { @(unlink($cagent) + unlink($dagent)); } } } } ob_start(); ++p::$ob_level; try { $data = (object) $a->compose((object) array()); if (!p::$is_enabled) { p::closeMeta(); return; } $template = $a->getTemplate(); echo '{'; $comma = ''; foreach ($data as $key => $value) { $key = jsquote($key); is_string($key) || ($key = "'" . $key . "'"); echo $comma, $key, ':'; if ($value instanceof \loop) { self::writeAgent($value); } else { echo jsquote($value); } $comma = ','; } echo '}'; } catch (e\PrivateResource $data) { ob_end_clean(); --p::$ob_level; p::closeMeta(); throw $data; } $data = ob_get_clean(); --p::$ob_level; $a->metaCompose(); list($maxage, $group, $expires, $watch, $headers) = p::closeMeta(); } catch (e\PrivateResource $data) { if ($liveAgent) { echo 'false";(window.E||alert)("You must provide an auth token to get this liveAgent:\\n"+', jsquote($_SERVER['REQUEST_URI']), ')'; echo '//</script><script src="' . p::__BASE__() . 'js/QJsrsHandler"></script>'; } else { if ($data->getMessage()) { echo 'w.r(0,' . (int) (!DEBUG) . '));'; } else { echo ');window.E&&E("You must provide an auth token to get this agent:\\n"+', jsquote($_SERVER['REQUEST_URI']), ')'; } } exit; } if ($liveAgent) { echo str_replace(array('\\', '"', '</'), array('\\\\', '\\"', '<\\/'), $data), '"//</script><script src="' . p::__BASE__() . 'js/QJsrsHandler"></script>'; } else { echo $data; } if ('ontouch' === $expires && !($watch || $config_maxage == $maxage)) { $expires = 'auto'; } $expires = 'auto' === $expires && ($watch || $config_maxage == $maxage) ? 'ontouch' : 'onmaxage'; $is_cacheable = $is_cacheable && !in_array('private', $group) && ($maxage || 'ontouch' === $expires); if (!$liveAgent || $is_cacheable) { if ($is_cacheable) { ob_start(); } if ($config_maxage == $maxage && Superloader::$turbo) { $ctemplate = p::getContextualCachePath("templates/{$template}", 'txt'); $readHandle = true; if ($h = p::fopenX($ctemplate, $readHandle)) { p::openMeta('agent__template/' . $template, false); $template = new \ptlCompiler_js($template); echo $template = ',' . $template->compile() . ')'; fwrite($h, $template); flock($h, LOCK_UN); fclose($h); list(, , , $template) = p::closeMeta(); p::writeWatchTable($template, $ctemplate); } else { fpassthru($readHandle); flock($readHandle, LOCK_UN); fclose($readHandle); } $watch[] = 'public/templates/js'; } else { echo ',[1,', jsquote($template), ',0,0,0])'; } if ($is_cacheable) { $ob = true; $template = array('maxage' => $maxage, 'expires' => $expires, 'watch' => $watch, 'headers' => $headers, 'rawdata' => $data); $expires = 'ontouch' === $expires ? $config_maxage : $maxage; if ($h = p::fopenX($dagent)) { fwrite($h, serialize($template)); flock($h, LOCK_UN); fclose($h); touch($dagent, $_SERVER['REQUEST_TIME'] + $expires); p::writeWatchTable($watch, $dagent); } if ($h = p::fopenX($cagent)) { $ob = false; $template['rawdata'] .= $liveAgent ? ob_get_clean() : ob_get_flush(); fwrite($h, serialize($template)); flock($h, LOCK_UN); fclose($h); touch($cagent, $_SERVER['REQUEST_TIME'] + $expires); p::writeWatchTable($watch, $cagent); } if ($ob) { $liveAgent ? ob_end_clean() : ob_end_flush(); } } } }
protected static function sendDebugInfo() { ob_start(function_exists('ob_gzhandler') ? 'ob_gzhandler' : null, 1 << 14); header('Content-Type: text/html; charset=utf-8'); header('Cache-Control: max-age=0,private,must-revalidate'); set_time_limit(0); ignore_user_abort(true); ?> <!doctype html> <html> <head> <title>Debug Window</title> <link rel="stylesheet" href="<?php echo p::__BASE__() . 'css/patchwork-console.css?' . $GLOBALS['patchwork_appId']; ?> "> </head> <body> <script src="<?php echo p::__BASE__() . 'js/patchwork-console.js?' . $GLOBALS['patchwork_appId']; ?> "></script> <div id="events" style="display:none"> <?php for (;;) { $continue = false; foreach (scandir(PATCHWORK_ZCACHE) as $log) { if ('.log' !== substr($log = PATCHWORK_ZCACHE . $log, -4)) { continue; } /**/ // On Windows only, rename() fails if the file is opened in an other process. /**/ // We use this behavior to detect this and cancel sending the file. /**/ if ('\\' === DIRECTORY_SEPARATOR) { if (!@rename($log, $log .= '~')) { $continue = true; continue; } /**/ } if (!($h = @fopen($log, 'rb'))) { /**/ if ('\\' === DIRECTORY_SEPARATOR) { rename($log, substr($log, 0, -1)); } continue; } /**/ if ('\\' !== DIRECTORY_SEPARATOR) { usleep(1); // Give priority for locking to the error handler process if (@flock($h, LOCK_EX | LOCK_NB, $j) && !$j) { unlink($log); } else { $continue = true; continue; } /**/ } $it = new p\PHP\JsonDumpIterator($h); try { unset($j); foreach ($it as $j) { echo '<script>patchworkConsole.log(', $it->jsonStr($j['type']), ',', $j['json'], ',', $it->jsonStr(substr(md5($log), -10)), ')</script>', "\n"; ob_flush(); flush(); if (connection_aborted()) { $continue = false; break; } } } catch (p\PHP\JsonDumpIteratorException $it) { } flock($h, LOCK_UN); fclose($h); /**/ if ('\\' === DIRECTORY_SEPARATOR) { unlink($log); } } if ($continue && isset($j)) { usleep(150000); } else { break; } } ?> </div> <script> scrollTo(0,0); var i, b = window.parent && parent.E && parent.E.buffer; for (i in b) patchworkConsole.log("client-dump", b[i]); parent.E.buffer = []; </script> <?php }
protected static function get_html(&$value, &$args) { $a = array(); if ($result = self::get_text($value, $a)) { $result = self::sanitizeHtml($result); $a = strip_tags($result); $a = html_entity_decode($a, ENT_COMPAT, 'UTF-8'); $a = preg_replace('/^[\\s\\pZ]+/u', '', $a); if ('' === $a) { $result = ''; } else { $result = preg_replace("'[ \t]+\$'m", '', trim($result)); $result = preg_replace("'\n{3,}'", "\n\n", $result); $result = preg_replace("'(?<!>)\n\n'", "<br>\n<br>\n", $result); $result = preg_replace("'(?<!>)\n'", "<br>\n", $result); $result = str_replace(array('{~}', '{/}', Patchwork::__BASE__(), Patchwork::__HOST__()), array('{~}', '{/}', '{~}', '{/}'), $result); } } return $result; }
static function filter($buffer, $mode) { static $rest = '', $base; if (!isset($base)) { $base = dirname($_SERVER['PATCHWORK_REQUEST'] . ' '); if (1 === strlen($base) && strspn($base, '/\\.')) { $base = ''; } $base = p::__BASE__() . $base . '/'; } $buffer = preg_split(self::$filterRx, $rest . $buffer, -1, PREG_SPLIT_DELIM_CAPTURE); $len = count($buffer); for ($i = 1; $i < $len; $i += 2) { $buffer[$i] .= $base; } if (PHP_OUTPUT_HANDLER_END & $mode) { $rest = ''; } else { --$len; $rest = substr($buffer[$len], 4096); $buffer[$len] = substr($buffer[$len], 0, 4096); } $buffer = implode('', $buffer); return $buffer; }
static function loadAgent($agent, $args, $is_exo) { if (null === $agent) { return; } $a =& $_GET; if (false === $args) { $reset_get = true; $cache = ''; if ('s' === p::$requestMode) { ob_start(array(__CLASS__, 'ob_htmlspecialchars'), 32768); ++p::$ob_level; self::$get = (object) $a; } else { $args = array(); if (is_array($a)) { reset($a); while (list($k, $v) = each($a)) { $args[$k] = is_string($v) ? htmlspecialchars($v) : $v; } } self::$get = (object) $args; } self::$get->__DEBUG__ = DEBUG ? DEBUG : 0; self::$get->__HOST__ = htmlspecialchars(p::__HOST__()); $cache .= self::$get->__LANG__ = htmlspecialchars(p::__LANG__()); $cache .= self::$get->__BASE__ = htmlspecialchars(p::__BASE__()); self::$get->__AGENT__ = 'agent_index' === $agent ? '' : p\Superloader::class2file(substr($agent, 6)) . '/'; self::$get->__URI__ = htmlspecialchars(p::$uri); self::$get->__REFERER__ = isset($_SERVER['HTTP_REFERER']) ? htmlspecialchars($_SERVER['HTTP_REFERER']) : ''; self::$get->__LANG_ALT__ = new \loop_altLang(); self::$args = self::$get; if (!isset(self::$masterCache[$cache])) { self::$masterCache[$cache] = array(); } self::$cache =& self::$masterCache[$cache]; } else { $reset_get = false; $_GET =& $args; if ($agent instanceof \loop && $agent->__toString()) { $agent->autoResolve = false; while ($i = $agent->loop()) { $data = $i; } if (!(p::$binaryMode || $agent instanceof LoopFreezed)) { foreach ($data as &$v) { is_string($v) && ($v = htmlspecialchars($v)); } } $agent = $data->{'a$'}; $args = array_merge((array) $data, $args); } $BASE = p::__BASE__(); $agent = p::base($agent, true); if (0 === strncmp($agent, $BASE, strlen($BASE))) { $agent = substr($agent, strlen($BASE)); if ($is_exo) { user_error("Patchwork Security Restriction Error: an AGENT ({$agent}) is called with EXOAGENT"); $_GET =& $a; return; } } else { if ($is_exo) { $k = $CONFIG['i18n.lang_list'][p::__LANG__()]; $agent = implode($k, explode('__', $agent, 2)) . '?p:=s'; foreach ($args as $k => $v) { $agent .= '&' . urlencode($k) . '=' . urlencode($v); } if (ini_get_bool('allow_url_fopen')) { $agent = file_get_contents($agent); } else { $agent = new \HTTP_Request($agent); $agent->sendRequest(); $agent = $agent->getResponseBody(); } echo str_replace(array('>', '<', '"', ''', '&'), array('>', '<', '"', "'", '&'), $agent); } else { user_error("Patchwork Security Restriction Error: an EXOAGENT ({$agent}) is called with AGENT"); } $_GET =& $a; return; } try { $agent = p::resolveAgentClass($agent, $args); } catch (e\StaticResource $agent) { readfile($agent->getMessage()); $_GET =& $a; return; } self::$args = (object) $args; } self::render($agent); $_GET =& $a; if ($reset_get) { self::$get = false; } }