function Streams_before_Q_responseExtras() { Q_Response::addScript('plugins/Streams/js/Streams.js'); $host = Q_Config::get('Streams', 'node', 'host', Q_Config::get('Q', 'node', 'host', null)); $port = Q_Config::get('Streams', 'node', 'port', Q_Config::get('Q', 'node', 'port', null)); $user = Users::loggedInUser(); if ($user) { Q_Response::setScriptData('Q.plugins.Users.loggedInUser.displayName', Streams::displayName($user)); } if (!Q_Request::isAjax()) { $invite_url = Q_Config::get('Streams', 'invite', 'url', "http://invites.to"); Q_Response::setScriptData('Q.plugins.Streams.invite.url', $invite_url); if (isset($host) && isset($port)) { Q_Response::setScriptData('Q.plugins.Streams.node', array("http://{$host}:{$port}")); } if ($sizes = Q_Config::expect('Streams', 'types', 'Streams/image', 'sizes')) { sort($sizes); Q_Response::setScriptData('Q.plugins.Streams.image.sizes', $sizes); } $defaults = array('readLevel' => Streams::$READ_LEVEL['messages'], 'writeLevel' => Streams::$WRITE_LEVEL['join'], 'adminLevel' => Streams::$ADMIN_LEVEL['invite']); Q_Response::setScriptData('Q.plugins.Streams.defaults', $defaults); if ($froalaKey = Q_Config::get('Streams', 'froala', 'key', null)) { Q_Response::setScriptData('Q.plugins.Streams.froala.key', $froalaKey); } } Q_Response::addStylesheet("plugins/Streams/css/Streams.css"); }
function MyApp_notFound_response_content($params) { header("HTTP/1.0 404 Not Found"); $url = Q_Request::url(); if (Q_Request::isAjax()) { throw new Q_Exception_NotFound(compact('url')); } return Q::view("MyApp/content/notFound.php", compact('url')); }
function Streams_participating_response() { if (!Q_Request::isAjax()) { return; } $max_limit = Q_Config::expect('Streams', 'db', 'limits', 'participating'); $user = Users::loggedInUser(true); $type = Streams::requestedType(); $limit = Streams::requestedField('limit', false, $max_limit); if ($limit > $max_limit) { throw new Q_Exception("limit is too large, must be <= {$max_limit}"); } $offset = Streams::requestedField('offset', false, 0); $order = Streams::requestedField('order', false, true); $participating = array(); $q = Streams_Participating::select('*')->where(array('userId' => $user->id)); if ($type) { $q = $q->where(array('streamName' => new Db_Range($type . '/', true, false, true))); } if ($limit) { $q = $q->limit($limit, $offset); } if ($order) { $q = $q->orderBy('updatedTime', false); } $res_participating = $q->fetchDbRows(); foreach ($res_participating as $part) { $part_safe = $part->exportArray(); if (isset($part_safe)) { $participating[] = $part_safe; } } Q_Response::setSlot('participating', $participating); if (!Q_Request::slotName('streams')) { return; } $res_streams = array(); $streamNames = array(); foreach ($res_participating as $p) { $streamNames[$p->publisherId][] = $p->streamName; } foreach ($streamNames as $p_id => $names) { $res_streams[$p_id] = Streams::fetch($user->id, $p_id, $names); } $streams = array(); $o = array('asUserId' => $user->id); foreach ($res_streams as $publisherId => $streams_array) { if (!empty($streams_array)) { $streams[$publisherId] = array(); foreach ($streams_array as $streamName => $stream) { $streams[$publisherId][$streamName] = $stream->exportArray($o); } } } Q_Response::setSlot('streams', $streams); }
/** * This is the default handler for the Q/responseExtras event. * It should not be invoked during AJAX requests, and especially * not during JSONP requests. It will output things like the nonce, * which prevents CSRF attacks, but is only supposed to be printed * on our webpages and not also given to anyone who does a JSONP request. */ function Q_before_Q_responseExtras() { $app = Q_Config::expect('Q', 'app'); $uri = Q_Dispatcher::uri(); $url = Q_Request::url(true); $base_url = Q_Request::baseUrl(); $ajax = Q_Request::isAjax(); if (!$uri) { return; } $info = array('url' => $url, 'uriString' => (string) $uri); if ($uri) { $info['uri'] = $uri->toArray(); } if (!$ajax) { $info = array_merge(array('app' => Q_Config::expect('Q', 'app')), $info, array('proxies' => Q_Config::get('Q', 'proxies', array()), 'baseUrl' => $base_url, 'proxyBaseUrl' => Q_Uri::url($base_url), 'proxyUrl' => Q_Uri::url($url), 'sessionName' => Q_Session::name(), 'nodeUrl' => Q_Utils::nodeUrl(), 'slotNames' => Q_Config::get("Q", "response", "slotNames", array('content', 'dashboard', 'title', 'notices')))); } foreach ($info as $k => $v) { Q_Response::setScriptData("Q.info.{$k}", $v); } if (!$ajax) { $uris = Q_Config::get('Q', 'javascript', 'uris', array()); $urls = array(); foreach ($uris as $u) { $urls["{$u}"] = Q_Uri::url("{$u}"); } Q_Response::setScriptData('Q.urls', $urls); } // Export more variables to inline js $nonce = isset($_SESSION['Q']['nonce']) ? $_SESSION['Q']['nonce'] : null; if ($nonce) { Q_Response::setScriptData('Q.nonce', $nonce); } // Attach stylesheets and scripts foreach (Q_Config::get('Q', 'javascript', 'responseExtras', array()) as $src => $b) { if (!$b) { continue; } Q_Response::addScript($src); } foreach (Q_Config::get('Q', 'stylesheets', 'responseExtras', array()) as $src => $media) { if (!$media) { continue; } if ($media === true) { $media = 'screen,print'; } Q_Response::addStylesheet($src, null, $media); } }
function Users_before_Q_responseExtras() { Q_Response::addScript('plugins/Users/js/Users.js'); $app = Q_Config::expect('Q', 'app'); $requireLogin = Q_Config::get('Users', 'requireLogin', array()); $rl_array = array(); foreach ($requireLogin as $rl => $value) { $rl_array[Q_Uri::url($rl)] = $value; } if (!Q_Request::isAjax()) { Q_Response::setScriptData('Q.plugins.Users.requireLogin', $rl_array); $successUrl = Q_Config::get('Users', 'uris', "{$app}/successUrl", "{$app}/home"); $afterActivate = Q_Config::get('Users', 'uris', "{$app}/afterActivate", $successUrl); $loginOptions = Q_Config::get('Users', 'login', array("identifierType" => 'email,mobile', "userQueryUri" => 'Users/user', "using" => "native,facebook", "noRegister" => false)); $loginOptions["afterActivate"] = Q_Uri::url($afterActivate); $loginOptions["successUrl"] = Q_Uri::url($successUrl); Q_Response::setScriptData('Q.plugins.Users.login.serverOptions', $loginOptions); $setIdentifierOptions = Q::take($loginOptions, array('identifierType')); Q_Response::setScriptData('Q.plugins.Users.setIdentifier.serverOptions', $setIdentifierOptions); } $fb_app_info = Q_Config::get('Users', 'facebookApps', $app, array()); if ($fb_app_info) { unset($fb_app_info['secret']); Q_Response::setScriptData("Q.plugins.Users.facebookApps.{$app}", $fb_app_info); } if ($node_server_url = Q_Config::get('Users', 'nodeServer', 'url', null)) { Q_Response::setScriptData("Q.plugins.Users.nodeServer", parse_url($node_server_url)); } if (Q_Config::get('Users', 'showLoggedInUser', true)) { $user = Q_Session::id() ? Users::loggedInUser() : null; if ($user) { $u = $user->exportArray(); $u['sessionCount'] = $user->sessionCount; Q_Response::setScriptData("Q.plugins.Users.loggedInUser", $u); Q_Response::addScriptLine("Q.plugins.Users.loggedInUser = new Q.plugins.Users.User(Q.plugins.Users.loggedInUser);"); } } Q_Response::setScriptData('Q.plugins.Users.communityId', Users::communityId()); Q_Response::setScriptData('Q.plugins.Users.communityName', Users::communityName()); Q_Response::setScriptData('Q.plugins.Users.communitySuffix', Users::communitySuffix()); Q_Response::setScriptData('Q.plugins.Users.hinted', Q::ifset($_SESSION, 'Users', 'hinted', array())); if ($sizes = Q_Config::expect('Users', 'icon', 'sizes')) { sort($sizes); Q_Response::setScriptData('Q.plugins.Users.icon.sizes', $sizes); } $defaultSize = Q_Config::get('Users', 'icon', 'defaultSize', 40); Q_Response::setScriptData('Q.plugins.Users.icon.defaultSize', $defaultSize); Q_Response::addStylesheet("plugins/Users/css/Users.css"); }
function Q_after_Q_tool_render($params, &$result) { $info = $params['info']; $extra = $params['extra']; if (!is_array($extra)) { $extra = array(); } $id_prefix = Q_Html::getIdPrefix(); $tool_ids = Q_Html::getToolIds(); $tag = Q::ifset($extra, 'tag', 'div'); if (empty($tag)) { Q_Html::popIdPrefix(); return; } $classes = ''; $data_options = ''; $count = count($info); foreach ($info as $name => $opt) { $classes = ($classes ? "{$classes} " : $classes) . implode('_', explode('/', $name)) . '_tool'; $options = Q_Response::getToolOptions($name); if (isset($options)) { $friendly_options = str_replace(array('"', '\\/'), array('"', '/'), Q_Html::text(Q::json_encode($options))); } else { $friendly_options = ''; } $normalized = Q_Utils::normalize($name, '-'); if (isset($options) or $count > 1) { $id = $tool_ids[$name]; $id_string = $count > 1 ? "{$id} " : ''; $data_options .= " data-{$normalized}='{$id_string}{$friendly_options}'"; } $names[] = $name; } if (isset($extra['classes'])) { $classes .= ' ' . $extra['classes']; } $attributes = isset($extra['attributes']) ? ' ' . Q_Html::attributes($extra['attributes']) : ''; $data_retain = !empty($extra['retain']) || Q_Response::shouldRetainTool($id_prefix) ? " data-Q-retain=''" : ''; $data_replace = !empty($extra['replace']) || Q_Response::shouldReplaceWithTool($id_prefix) ? " data-Q-replace=''" : ''; $names = $count === 1 ? ' ' . key($info) : 's ' . implode(" ", $names); $ajax = Q_Request::isAjax(); $result = "<{$tag} id='{$id_prefix}tool' " . "class='Q_tool {$classes}'{$data_options}{$data_retain}{$data_replace}{$attributes}>" . "{$result}</{$tag}>"; if (!Q_Request::isAjax()) { $result = "<!--\nbegin tool{$names}\n-->{$result}<!--\nend tool{$names} \n-->"; } Q_Html::popIdPrefix(); }
function Q_exception_native($params) { extract($params); /** * @var Exception $exception */ if ($is_ajax = Q_Request::isAjax()) { $json = @Q::json_encode(array('errors' => Q_Exception::toArray(array($exception)))); $callback = Q_Request::callback(); switch (strtolower($is_ajax)) { case 'iframe': // Render an HTML layout for ajax if (!Q_Response::$batch) { header("Content-type: text/html"); } echo <<<EOT <!doctype html><html lang=en> <head><meta charset=utf-8><title>Q Result</title></head> <body> <script type="text/javascript"> window.result = function () { return {$json} }; </script> </body> </html> EOT; break; case 'json': // Render a JSON layout for ajax // Render a JSON layout for ajax default: header("Content-type: " . ($callback ? "application/javascript" : "application/json")); echo $callback ? "{$callback}({$json})" : $json; } } else { if (Q::textMode()) { echo Q_Exception::coloredString($exception); exit; } $message = $exception->getMessage(); $file = $exception->getFile(); $line = $exception->getLine(); if (is_callable(array($exception, 'getTraceAsStringEx'))) { $trace_string = $exception->getTraceAsStringEx(); } else { $trace_string = $exception->getTraceAsString(); } if ($exception instanceof Q_Exception_PhpError or !empty($exception->messageIsHtml)) { // do not sanitize $message } else { $message = Q_Html::text($message); } $content = "<h1 class='exception_message'>{$message}</h1>"; if (Q_Config::get('Q', 'exception', 'showFileAndLine', true)) { $content .= "<h3 class='exception_fileAndLine'>in {$file} ({$line})</h3>"; } if (Q_Config::get('Q', 'exception', 'showTrace', true)) { $content .= "<pre class='exception_trace'>{$trace_string}</pre>"; } $content .= str_repeat(' ', 512); // because of chrome $title = "Exception occurred"; $dashboard = ""; echo Q::view('Q/layout/html.php', compact('content', 'dashboard', 'title')); } $app = Q_Config::get('Q', 'app', null); $colored = Q_Exception::coloredString($exception); Q::log("{$app}: Exception in " . ceil(Q::milliseconds()) . "ms:\n\n{$colored}\n", null, true, array('maxLength' => 10000)); }
/** * @method writeHandler * @static * @param {string} $id * @param {string} $sess_data * @return {boolean} */ static function writeHandler($id, $sess_data) { try { // if the request is AJAX request that came without session cookie, then do not write session, ignore it if (Q_Request::isAjax() && !isset($_COOKIE[self::name()])) { return false; } // don't save sessions when running from command-line (cli) if (php_sapi_name() == 'cli') { return false; } /** * @event Q/session/write {before} * @param {string} id * @param {string} sess_data * @return {boolean} */ if (false === Q::event('Q/session/write', compact('id', 'sess_data'), 'before')) { return false; } if (empty(self::$session_save_path)) { self::$session_save_path = self::savePath(); } if (!empty(self::$session_db_connection)) { // Create a new row to be saved in the session table $db_row_class = self::$session_db_row_class; // Make sure it has a primary key! if (count(self::$session_db_row->getPrimaryKey()) != 1) { throw new Q_Exception("The primary key of " . self::$session_db_row_class . " has to consist of exactly 1 field!"); } $id_field = self::$session_db_id_field; $data_field = self::$session_db_data_field; $updated_field = self::$session_db_updated_field; $duration_field = self::$session_db_duration_field; $row = self::$session_db_row; if (!$row->wasRetrieved()) { $row->{$id_field} = $id; } $row->{$data_field} = $sess_data; $row->{$duration_field} = Q_Config::get('Q', 'session', 'durations', Q_Request::formFactor(), Q_Config::expect('Q', 'session', 'durations', 'session')); /** * @event Q/session/save {before} * @param {string} id * @param {string} sess_data * @return {boolean} */ if (false === Q::event('Q/session/save', array('row' => $row, 'id_field' => $id_field, 'data_field' => $data_field, 'updated_field' => $updated_field, 'duration_field' => $duration_field), 'before')) { return false; } $row->save(false, true); $result = true; } else { $duration_name = self::durationName(); $id1 = substr($id, 0, 4); $id2 = substr($id, 4); $ssp = self::$session_save_path; $sess_file = $ssp . DS . "{$duration_name}/{$id1}/{$id2}"; $dir = $ssp . DS . "{$duration_name}/{$id1}/"; if (!is_dir($dir)) { mkdir($dir, fileperms($ssp), true); } if (!is_writable($dir)) { // alert the developer to this problem Q::log("{$sess_file} is not writable", 'fatal'); die("{$sess_file} is not writable"); } $fp = fopen($sess_file, "w"); if (!$fp) { return false; } $result = fwrite($fp, $sess_data); fclose($fp); } $changed = $sess_data !== self::$sess_data; $old_data = self::$sess_data; /** * @event Q/session/write {after} * @param {string} id * @param {string} sess_data * @param {string} data_field * @param {string} updated_field * @param {string} duration_field * @param {string} sess_file * @param {integer} row * @param {boolean} changed * @param {string} old_data * @return {mixed} */ $result = Q::event('Q/session/write', compact('id', 'sess_data', 'data_field', 'updated_field', 'duration_field', 'sess_file', 'row', 'changed', 'old_data'), 'after'); return $result; } catch (Exception $e) { Q::log("Exception when writing session {$id}: " . $e->getMessage()); throw $e; } }
/** * Sets a header to redirect to a given URI or URL. * @method redirect * @static * @param {string} $uri The URL or internal URI to redirect to * @param {array} $options An array of options that can include: * "loop" => Defaults to false. If true, sets the redirect header even if the current URL is the same. * "noProxy" => Defaults to false. If true, doesn't use the proxy mapping to determine URL * "permanently" => If true, sets response code as 304 instead of 302 * @param {boolean} [$noProxy=false] * @return {boolean} * Return whether the redirect header was set. */ static function redirect($uri, $options = array()) { extract($options); $url = Q_Uri::url($uri, null, !empty($noProxy)); if ($url === Q_Uri::unreachableUri()) { throw new Q_Exception_BadValue(array('internal' => 'uri', 'problem' => 'no url routes to it')); } $level = ob_get_level(); for ($i = 0; $i < $level; ++$i) { ob_clean(); } /** * @event Q/response {before} * @param {string} permanently * @param {string} uri * @param {string} url * @param {string} loop * @return {boolean} */ $result = Q::event('Q/redirect', compact('uri', 'url', 'loop', 'permanently', 'noProxy', 'level'), 'before'); if (isset($result)) { return $result; } if (!empty($loop) and Q_Request::url() === $url) { return false; } if (!Q_Request::isAjax()) { if (!empty($permanently)) { header("HTTP/1.1 301 Moved Permanently"); } header("Location: {$url}"); } self::$redirected = $uri; return true; }
/** * The default implementation. */ function Q_errors($params) { extract($params); /** * @var Exception $exception * @var boolean $startedResponse */ if (!empty($exception)) { Q_Response::addError($exception); } $errors = Q_Response::getErrors(); $errors_array = Q_Exception::toArray($errors); // Simply return the errors, if this was an AJAX request if ($is_ajax = Q_Request::isAjax()) { try { $errors_json = @Q::json_encode($errors_array); } catch (Exception $e) { $errors_array = array_slice($errors_array, 0, 1); unset($errors_array[0]['trace']); $errors_json = @Q::json_encode($errors_array); } $json = "{\"errors\": {$errors_json}}"; $callback = Q_Request::callback(); switch (strtolower($is_ajax)) { case 'iframe': if (!Q_Response::$batch) { header("Content-type: text/html"); } echo <<<EOT <!doctype html><html lang=en> <head><meta charset=utf-8><title>Q Result</title></head> <body> <script type="text/javascript"> window.result = function () { return {$json} }; </script> </body> </html> EOT; break; case 'json': default: header("Content-type: " . ($callback ? "application/javascript" : "application/json")); echo $callback ? "{$callback}({$json})" : $json; } return; } // Forward internally, if it was requested if ($onErrors = Q_Request::special('onErrors', null)) { $uri1 = Q_Dispatcher::uri(); $uri2 = Q_Uri::from($onErrors); $url2 = $uri2->toUrl(); if (!isset($uri2)) { throw new Q_Exception_WrongValue(array('field' => 'onErrors', 'range' => 'an internal URI reachable from a URL')); } if ($uri1->toUrl() !== $url2) { Q_Dispatcher::forward($uri2); return; // we don't really need this, but it's here anyway } } $params2 = compact('errors', 'exception', 'errors_array', 'exception_array'); if (Q::eventStack('Q/response')) { // Errors happened while rendering response. Just render errors view. return Q::view('Q/errors.php', $params2); } if (!$startedResponse) { try { // Try rendering the response, expecting it to // display the errors along with the rest. $ob = new Q_OutputBuffer(); Q::event('Q/response', $params2); $ob->endFlush(); return; } catch (Exception $e) { if (get_class($e) === 'Q_Exception_DispatcherForward') { throw $e; // if forwarding was requested, do it // for all other errors, continue trying other things } $output = $ob->getClean(); } } if ($errors) { // Try rendering the app's errors response, if any. $app = Q::app(); if (Q::canHandle("{$app}/errors/response/content")) { Q_Dispatcher::forward("{$app}/errors"); } else { echo Q::view("Q/errors.php", compact('errors')); } } if (!empty($e)) { return Q::event('Q/exception', array('exception' => $e)); } }
/** * Default Q/response handler. * 1. Gets some slots, depending on what was requested. * 2. Renders them in a layout * The layout expects "title", "dashboard" and "contents" slots to be filled. */ function Q_response($params) { extract($params); /** * @var Exception $exception * @var array $errors */ if (empty($errors)) { $errors = Q_Response::getErrors(); } if (!empty($_GET['Q_ct'])) { Q_Response::setCookie('Q_ct', $_GET['Q_ct']); } // If output is set, use that $output = Q_Response::output(); if (isset($output)) { if ($output === true) { return; } if (is_string($output)) { echo $output; } return; } // Redirect to success page, if requested. $isAjax = Q_Request::isAjax(); if (empty($errors) and empty($exception)) { if (!$isAjax and null !== Q_Request::special('onSuccess', null)) { $onSuccess = Q_Request::special('onSuccess', null); if (Q_Config::get('Q', 'response', 'onSuccessShowFrom', true)) { $onSuccess = Q_Uri::url($onSuccess . '?Q.fromSuccess=' . Q_Dispatcher::uri()); } Q_Response::redirect($onSuccess); return; } } // Get the requested module $uri = Q_Dispatcher::uri(); if (!isset($module)) { $module = $uri->module; if (!isset($module)) { $module = 'Q'; Q_Dispatcher::uri()->module = 'Q'; } } if (!$isAjax || Q_Request::isLoadExtras()) { Q::event('Q/responseExtras', array(), 'before'); } // Get the main module (the app) $app = Q_Config::expect('Q', 'app'); $action = $uri->action; if (Q::canHandle("{$module}/{$action}/response")) { if (false === Q::event("{$module}/{$action}/response") and !$isAjax) { return; } } $slotNames = Q_Request::slotNames(true); $idPrefixes = array(); if ($temp = Q_Request::special('idPrefixes', null)) { foreach (explode(',', $temp) as $i => $prefix) { if (!isset($slotNames[$i])) { throw new Q_Exception("More id prefixes than slot names", "Q.idPrefixes"); } $idPrefixes[$slotNames[$i]] = $prefix; } } // What to do if this is an AJAX request if ($isAjax) { $to_encode = array(); if (Q_Response::$redirected) { // We already called Q_Response::redirect $to_encode['redirect']['url'] = Q_Uri::url(Q_Response::$redirected); try { $to_encode['redirect']['uri'] = Q_Uri::from(Q_Response::$redirected)->toArray(); } catch (Exception $e) { // couldn't get internal URI } } else { if (is_array($slotNames)) { foreach ($slotNames as $slotName) { Q_Response::fillSlot($slotName, 'default', Q::ifset($idPrefixes, $slotName, null)); } // Go through the slots again, because other handlers may have overwritten // their contents using Q_Response::setSlot() foreach ($slotNames as $sn) { Q_Response::fillSlot($sn, 'default', Q::ifset($idPrefixes, $slotName, null)); } if (Q_Response::$redirected) { // While rendering the slots we called Q_Redirect $to_encode['redirect']['url'] = Q_Uri::url(Q_Response::$redirected); try { $to_encode['redirect']['uri'] = Q_Uri::from(Q_Response::$redirected)->toArray(); } catch (Exception $e) { // couldn't get internal URI } } else { if (Q_Request::isLoadExtras()) { $to_encode['slots'] = Q_Response::slots(true); // add stylesheets, stylesinline, scripts, scriptlines, scriptdata, templates foreach (array_merge(array(''), $slotNames) as $slotName) { $temp = Q_Response::stylesheetsArray($slotName); if ($temp) { $to_encode['stylesheets'][$slotName] = $temp; } $temp = Q_Response::stylesInline($slotName); if ($temp) { $to_encode['stylesInline'][$slotName] = $temp; } $temp = Q_Response::scriptsArray($slotName); if ($temp) { $to_encode['scripts'][$slotName] = $temp; } $temp = Q_Response::scriptLines($slotName, true, "\n", false); if ($temp) { $to_encode['scriptLines'][$slotName] = $temp; } $temp = Q_Response::scriptData($slotName); if ($temp) { $to_encode['scriptData'][$slotName] = $temp; } $temp = Q_Response::templateData($slotName); if ($temp) { $to_encode['templates'][$slotName] = $temp; } } } else { $to_encode['slots'] = Q_Response::slots(true); // add stylesinline, scriptlines, scriptdata, templates foreach (array_merge(array(''), $slotNames) as $slotName) { $temp = Q_Response::stylesInline($slotName); if ($temp) { $to_encode['stylesInline'][$slotName] = $temp; } $temp = Q_Response::scriptData($slotName); if ($temp) { $to_encode['scriptData'][$slotName] = $temp; } $temp = Q_Response::scriptLines($slotName, true, "\n", false); if ($temp) { $to_encode['scriptLines'][$slotName] = $temp; } } } } } } $to_encode['timestamp'] = microtime(true); $echo = Q_Request::contentToEcho(); if (isset($echo)) { $to_encode['echo'] = $echo; } $json = Q::json_encode(Q::cutoff($to_encode)); $callback = Q_Request::callback(); switch (strtolower($isAjax)) { case 'iframe': if (!Q_Response::$batch) { header("Content-type: text/html"); } echo <<<EOT <!doctype html><html lang=en> <head><meta charset=utf-8><title>Q Result</title></head> <body> <script type="text/javascript"> window.result = function () { return {$json} }; </script> </body> </html> EOT; break; case 'json': default: if (!Q_Response::$batch) { header("Content-type: " . ($callback ? "application/javascript" : "application/json")); } echo $callback ? "{$callback}({$json})" : $json; } return; } // If this is a request for a regular webpage, // fill the usual slots and render a layout. if (Q_Response::$redirected) { return; // If already set a redirect header, simply return -- no reason to output all this HTML } static $added_Q_init = false; if (!$added_Q_init) { Q_Response::addScriptLine("\n// Now, initialize Q\nQ.init();\n", null, 'Q'); $added_Q_init = true; } // Get all the usual slots for a webpage $slots = array(); foreach ($slotNames as $sn) { Q_Response::fillSlot($sn, 'default', Q::ifset($idPrefixes, $sn, null)); } // Go through the slots again, because other handlers may have overwritten // their contents using Q_Response::setSlot() foreach ($slotNames as $sn) { Q_Response::fillSlot($sn, 'default', Q::ifset($idPrefixes, $sn, null)); } $output = Q_Response::output(); if (isset($output)) { if ($output === true) { return; } if (is_string($output)) { echo $output; } return; } if (!$isAjax or Q_Request::isLoadExtras()) { Q::event('Q/responseExtras', array(), 'after'); } $slots = Q_Response::slots(false); // Render a full HTML layout $layout_view = Q_Response::layoutView(); echo Q::view($layout_view, $slots); }
/** * @method writeHandler * @static * @param {string} $id * @param {string} $sess_data * @return {boolean} */ static function writeHandler($id, $sess_data) { try { // if the request is AJAX request that came without session cookie, then do not write session, ignore it if (Q_Request::isAjax() && !isset($_COOKIE[self::name()])) { return false; } // don't save sessions when running from command-line (cli) if (php_sapi_name() == 'cli') { return false; } $our_SESSION = $_SESSION; $old_data = self::$sess_data; $changed = $sess_data !== $old_data; $result = false; /** * @event Q/session/write {before} * @param {string} id * @param {string} sess_data * @param {string} old_data * @param {boolean} changed * @return {boolean} */ if (false === Q::event('Q/session/write', compact('id', 'sess_data', 'old_data', 'changed'), 'before')) { return false; } if (empty(self::$session_save_path)) { self::$session_save_path = self::savePath(); } if (!empty(self::$session_db_connection)) { // Create a new row to be saved in the session table $db_row_class = self::$session_db_row_class; // Make sure it has a primary key! if (count(self::$session_db_row->getPrimaryKey()) != 1) { throw new Q_Exception("The primary key of " . self::$session_db_row_class . " has to consist of exactly 1 field!"); } $id_field = self::$session_db_id_field; $data_field = self::$session_db_data_field; $updated_field = self::$session_db_updated_field; $duration_field = self::$session_db_duration_field; $row = self::$session_db_row; $row->{$id_field} = $id; } else { $duration_name = self::durationName(); $id1 = substr($id, 0, 4); $id2 = substr($id, 4); $ssp = self::$session_save_path; $sess_file = $ssp . DS . "{$duration_name}/{$id1}/{$id2}"; $dir = $ssp . DS . "{$duration_name}/{$id1}/"; } if ($changed) { // Apparently, we want to save some changes. // The convention to avoid locking is that everything // stored in sessions must be mergeable using the // Q_Tree merge algorithm. // So we will retrieve the latest session data again, // merge our changes over it, and save. $params = array('id_field' => $id_field, 'data_field' => $data_field, 'updated_field' => $updated_field, 'duration_field' => $duration_field, 'changed' => $changed, 'sess_data' => $sess_data, 'old_data' => $old_data); if (!empty(self::$session_db_connection)) { $row->retrieve(); $existing_data = Q::ifset($row, $data_field, ""); $params['row'] = $row; } else { if (!is_dir($dir)) { mkdir($dir, fileperms($ssp), true); } if (!is_writable($dir)) { // alert the developer to this problem Q::log("{$sess_file} is not writable", 'fatal'); die("{$sess_file} is not writable"); } $file = fopen($sess_file, "w"); if (!$file) { return false; } $params['row'] = $row; $maxlength = Q_Config::get('Q', 'session', 'maxlength', 4095); $existing_data = fread($file, $maxlength); } $_SESSION = session_decode($existing_data); if (!$_SESSION) { $_SESSION = array(); } $t = new Q_Tree($_SESSION); $t->merge($our_SESSION); $_SESSION = $t->getAll(); $params['existing_data'] = $existing_data; $params['merged_data'] = $merged_data = session_encode(); /** * @event Q/session/save {before} * @param {string} sess_data * @param {string} old_data * @param {string} existing_data * @param {string} merged_data * @param {boolean} changed * @param {Db_Row} row * @return {boolean} */ if (false === Q::event('Q/session/save', $params, 'before')) { return false; } if (!empty(self::$session_db_connection)) { $row->{$data_field} = $merged_data; $row->{$duration_field} = Q_Config::get('Q', 'session', 'durations', Q_Request::formFactor(), Q_Config::expect('Q', 'session', 'durations', 'session')); $row->save(); $result = true; } else { $result = fwrite($file, $merged_data); fclose($file); } } /** * @event Q/session/write {after} * @param {string} id * @param {boolean} changed * @param {string} sess_data * @param {string} old_data * @param {string} existing_data * @param {string} merged_data * @param {string} data_field * @param {string} updated_field * @param {string} duration_field * @param {string} sess_file * @param {integer} row * @return {mixed} */ $result = Q::event('Q/session/write', compact('id', 'data_field', 'updated_field', 'duration_field', 'sess_file', 'row', 'changed', 'sess_data', 'old_data', 'existing_data', 'merged_data'), 'after'); return $result; } catch (Exception $e) { Q::log("Exception when writing session {$id}: " . $e->getMessage()); throw $e; } }