This method can read the client protocol from the "X-Forwarded-Proto" header
when trusted proxies were set via "setTrustedProxies()".
The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
If your reverse proxy uses a different header name than "X-Forwarded-Proto"
("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with
the "client-proto" key.
public function fromRequest(Request $request) { $this->setBaseUrl($request->getBaseUrl()); $this->setMethod($request->getMethod()); $this->setHost($request->getHost()); $this->setScheme($request->getScheme()); $this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort()); $this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort); }
/** * {@inheritDoc} */ public function getPath($relativePath, $isFlushable) { $container = $this->container; $object = $container->get_object($relativePath); if ($this->request && $this->request->isSecure()) { return $object->public_ssl_uri(); } else { return $object->public_uri(); } }
/** * Updates the RequestContext info based on a HttpFoundation Request. * * @param Request $request A Request instance */ public function fromRequest(Request $request) { $this->setBaseUrl($request->getBaseUrl()); $this->setPathInfo($request->getPathInfo()); $this->setMethod($request->getMethod()); $this->setHost($request->getHost()); $this->setScheme($request->getScheme()); $this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort()); $this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort); $this->setQueryString($request->server->get('QUERY_STRING', '')); }
protected function initializeRequestAttributes(Request $request, $master) { if ($master) { // set the context even if the parsing does not need to be done // to have correct link generation $this->router->setContext(array('base_url' => $request->getBaseUrl(), 'method' => $request->getMethod(), 'host' => $request->getHost(), 'port' => $request->getPort(), 'is_secure' => $request->isSecure())); } if ($request->attributes->has('_controller')) { // routing is already done return; } // add attributes based on the path info (routing) try { $parameters = $this->router->match($request->getPathInfo()); if (null !== $this->logger) { $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], json_encode($parameters))); } $request->attributes->add($parameters); if ($locale = $request->attributes->get('_locale')) { $request->getSession()->setLocale($locale); } } catch (NotFoundException $e) { $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo()); if (null !== $this->logger) { $this->logger->err($message); } throw new NotFoundHttpException($message, $e); } catch (MethodNotAllowedException $e) { $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods()))); if (null !== $this->logger) { $this->logger->err($message); } throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e); } }
/** * {@inheritdoc} */ public function isSecure() { if (null !== $this->isSecure) { return $this->isSecure; } if (parent::isSecure()) { return $this->isSecure = true; } // It may happen that some misconfigured environments won't set // the $_SERVER['HTTPS'] variable, we need another way to detect // this, either using Drupal, or port in use. if (443 === (int) $this->server->get('SERVER_PORT', 80)) { return $this->isSecure = true; } // Worst than misconfigured, we actually have no idea about what's // what because FPM or any other CGI gives us nothing goog to read, // let's just trust Drupal and pray. if ($GLOBALS['is_https']) { return $this->isSecure = true; } // The Drupal base URL might have been hardcoded in settings.php so // let's use that as last resort. if ('https://' === substr($GLOBALS['base_url'], 0, 8)) { return $this->isSecure = true; } return $this->isSecure = false; }
public function isUrlLocal($link) { if (!$this->request) { return false; } $parts = parse_url($link); $isLocal = true; if (!empty($parts['host']) && $parts['host'] !== $this->request->getHost()) { $isLocal = false; } elseif (!empty($parts['port']) && $parts['port'] !== $this->request->getPort()) { $isLocal = false; } elseif (!empty($parts['scheme']) && $this->request->isSecure() && $parts['scheme'] !== 'https') { // going out from secure connection to insecure page on same domain is not local $isLocal = false; } return $isLocal; }
/** * Login route. * * @param \Silex\Application $app * @param Request $request * * @return Response */ public function authenticationLogin(Application $app, Request $request) { if (!$request->isSecure()) { // Log a warning if this route is not HTTPS $msg = sprintf("[ClientLogin][Controller]: Login route '%s' is not being served over HTTPS. This is insecure and vulnerable!", $request->getPathInfo()); $app['logger.system']->critical($msg, ['event' => 'extensions']); } $this->setFinalRedirectUrl($app, $request); $response = $this->getFinalResponse($app, 'login'); return $response; }
/** * Returns the session cookie name. * * @param \Symfony\Component\HttpFoundation\Request $request * The request. * * @return string * The name of the session cookie. */ protected function getName(Request $request) { // To prevent session cookies from being hijacked, a user can configure the // SSL version of their website to only transfer session cookies via SSL by // using PHP's session.cookie_secure setting. The browser will then use two // separate session cookies for the HTTPS and HTTP versions of the site. So // we must use different session identifiers for HTTPS and HTTP to prevent a // cookie collision. $prefix = $request->isSecure() ? 'SSESS' : 'SESS'; return $prefix . $this->getUnprefixedName($request); }
/** * Sets all needed values from the request. * * @param Request $request A request to get values from. */ public function setRequest(Request $request) { $this->setScheme($request->getScheme()); $this->setHost($request->getHost()); $this->setBasePath($request->getBasePath()); if ($request->isSecure()) { $this->setHttpsPort($request->getPort()); } else { $this->setHttpPort($request->getPort()); } }
/** * Checks if the user should be forced to use SSL connections. * * @param Request $request Request to check. * @return boolean|\Symfony\Component\HttpFoundation\RedirectResponse False * if the redirect is not needed and redirect response object otherwise. */ protected function sslRedirect(Request $request) { $need_redirect = Settings::get('enablessl') == '1' && Settings::get('forcessl') == '1' && !$request->isSecure(); if (!$need_redirect) { return false; } if (null !== ($qs = $request->getQueryString())) { $qs = '?' . $qs; } $path = 'https://' . $request->getHttpHost() . $request->getBasePath() . $request->getPathInfo() . $qs; return $this->redirect($path); }
/** * @param Request $request * @return Response */ protected function handle(Request $request) { $vars = array('isSecure' => $request->isSecure()); if (array_key_exists('User', $_SESSION) && $_SESSION['User'] == "Default User" && plugin_find_id("auth") >= 0) { if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != "off") { $vars['protocol'] = "HTTPS"; } else { $vars['protocol'] = preg_replace("@/.*@", "", @$_SERVER['SERVER_PROTOCOL']); } $vars['referrer'] = "?mod=browse"; $vars['authUrl'] = "?mod=auth"; } return $this->render("home.html.twig", $this->mergeWithDefault($vars)); }
/** * Login page and "Forgotten password" page. * * @param \Symfony\Component\HttpFoundation\Request $request * @param boolean $resetCookies * * @return \Bolt\Response\BoltResponse|\Symfony\Component\HttpFoundation\RedirectResponse */ public function getLogin(Request $request, $resetCookies = false) { $user = $this->getUser(); if ($user && $user->getEnabled() == 1) { return $this->redirectToRoute('dashboard'); } if ($this->getOption('general/enforce_ssl') && !$request->isSecure()) { return $this->redirect(preg_replace('/^http:/i', 'https:', $request->getUri())); } $response = $this->render('@bolt/login/login.twig', ['randomquote' => true]); $response->setVary('Cookies', false)->setMaxAge(0)->setPrivate(); if ($resetCookies) { $response->headers->clearCookie($this->app['token.authentication.name']); } return $response; }
public function start(Request $request, AuthenticationException $authException = null) { $scheme = $request->isSecure() ? 'http' : 'https'; if ('http' === $scheme && 80 != $this->httpPort) { $port = ':' . $this->httpPort; } elseif ('https' === $scheme && 443 != $this->httpsPort) { $port = ':' . $this->httpsPort; } else { $port = ''; } $qs = $request->getQueryString(); if (null !== $qs) { $qs = '?' . $qs; } $url = $scheme . '://' . $request->getHost() . $port . $request->getBaseUrl() . $request->getPathInfo() . $qs; return new RedirectResponse($url, 301); }
public function start(EventInterface $event, Request $request, AuthenticationException $authException = null) { $scheme = $request->isSecure() ? 'http' : 'https'; if ('http' === $scheme && 80 != $this->httpPort) { $port = ':' . $this->httpPort; } elseif ('https' === $scheme && 443 != $this->httpPort) { $port = ':' . $this->httpsPort; } else { $port = ''; } $qs = $request->getQueryString(); if (null !== $qs) { $qs = '?' . $qs; } $url = $scheme . '://' . $request->getHost() . $port . $request->getScriptName() . $request->getPathInfo() . $qs; $response = new Response(); $response->setRedirect($url, 301); return $response; }
protected function initializeRequestAttributes(Request $request, $master) { if ($master) { // set the context even if the parsing does not need to be done // to have correct link generation $this->router->setContext(array('base_url' => $request->getBaseUrl(), 'method' => $request->getMethod(), 'host' => $request->getHost(), 'is_secure' => $request->isSecure())); } if ($request->attributes->has('_controller')) { // routing is already done return; } // add attributes based on the path info (routing) if (false !== ($parameters = $this->router->match($request->getPathInfo()))) { if (null !== $this->logger) { $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], str_replace("\n", '', var_export($parameters, true)))); } $request->attributes->add($parameters); if ($locale = $request->attributes->get('_locale')) { $request->getSession()->setLocale($locale); } } elseif (null !== $this->logger) { $this->logger->err(sprintf('No route found for %s', $request->getPathInfo())); } }
/** * Get the full URL to the media, and in case switch between multiple CDNs * * @param boolean $thumbnail True if looking for a thumbnail, false for full media * * @return null|string Null if not available, string of the url if available */ public function getLink(Request $request, $thumbnail = false, $download = false) { $before = \Foolz\Plugin\Hook::forge('Foolz\\Foolfuuka\\Model\\Media::getLink.call.before.method.body')->setObject($this)->setParams(['thumbnail' => $thumbnail])->execute()->get(); if (!$before instanceof \Foolz\Plugin\Void) { return $before; } $image = null; if ($this->config->get('foolz/foolfuuka', 'config', 'media.filecheck') === true) { // locate the image if ($thumbnail && file_exists($this->getDir($thumbnail)) !== false) { if ($this->op == 1) { $image = $this->media->preview_op ?: $this->media->preview_reply; } else { $image = $this->media->preview_reply ?: $this->media->preview_op; } } // full image if (!$thumbnail && file_exists($this->getDir(false)) !== false) { $image = $this->media->media; } // fallback if we have the full image but not the thumbnail if ($thumbnail && $image === null && file_exists($this->getDir(false))) { $thumbnail = false; $image = $this->media->media; } } else { // locate the image if ($thumbnail) { if ($this->op == 1) { $image = $this->media->preview_op ?: $this->media->preview_reply; } else { $image = $this->media->preview_reply ?: $this->media->preview_op; } } else { if ($this->radix->archive && !$this->radix->getValue('archive_full_images')) { return null; } else { $image = $this->media->media; } } } if ($image !== null) { if ($download === true && $this->preferences->get('foolfuuka.boards.media_download_url')) { return $this->preferences->get('foolfuuka.boards.media_download_url') . '/' . $this->radix->shortname . '/' . ($thumbnail ? 'thumb' : 'image') . '/' . substr($image, 0, 4) . '/' . substr($image, 4, 2) . '/' . $image; } if ($request->isSecure() && $this->preferences->get('foolfuuka.boards.media_balancers_https')) { $balancers = $this->preferences->get('foolfuuka.boards.media_balancers_https'); } if (!isset($balancers) && $this->preferences->get('foolfuuka.boards.media_balancers')) { $balancers = $this->preferences->get('foolfuuka.boards.media_balancers'); } $media_cdn = []; if (isset($balancers)) { $media_cdn = array_filter(preg_split('/\\r\\n|\\r|\\n/', $balancers)); } if (!empty($media_cdn) && $this->media->media_id > 0) { return $media_cdn[$this->media->media_id % count($media_cdn)] . '/' . $this->radix->shortname . '/' . ($thumbnail ? 'thumb' : 'image') . '/' . substr($image, 0, 4) . '/' . substr($image, 4, 2) . '/' . $image; } return $this->preferences->get('foolfuuka.boards.url') . '/' . $this->radix->shortname . '/' . ($thumbnail ? 'thumb' : 'image') . '/' . substr($image, 0, 4) . '/' . substr($image, 4, 2) . '/' . $image; } if ($thumbnail && $this->media->media_status === 'normal') { $this->media->media_status = 'not-available'; } return null; }
public function testOverrideGlobals() { $request = new Request(); $request->initialize(array('foo' => 'bar')); // as the Request::overrideGlobals really work, it erase $_SERVER, so we must backup it $server = $_SERVER; $request->overrideGlobals(); $this->assertEquals(array('foo' => 'bar'), $_GET); $request->initialize(array(), array('foo' => 'bar')); $request->overrideGlobals(); $this->assertEquals(array('foo' => 'bar'), $_POST); $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); $request->headers->set('X_FORWARDED_PROTO', 'https'); $this->assertTrue($request->isSecure()); $request->overrideGlobals(); $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); // restore initial $_SERVER array $_SERVER = $server; }
private function assembleRedirectUrl($path, Request $request) { $proto = $request->isSecure() ? 'https' : 'http'; $url = sprintf('%s://%s%s%s', $proto, $request->getHost(), $request->getBaseUrl(), $path); return urlencode($url); }
/** * Get the full URL to the media, and in case switch between multiple CDNs * * @param boolean $thumbnail True if looking for a thumbnail, false for full media * * @return null|string Null if not available, string of the url if available */ public function getLink(Request $request, $thumbnail = false, $download = false) { $before = Hook::forge('Foolz\\FoolFuuka\\Model\\Media::getLink#exec.beforeMethod')->setObject($this)->setParams(['thumbnail' => $thumbnail])->execute()->get(); if (!$before instanceof \Foolz\Plugin\Void) { return $before; } if ($thumbnail) { if ($this->op == 1) { $image = $this->media->preview_op ?: $this->media->preview_reply; } else { $image = $this->media->preview_reply ?: $this->media->preview_op; } } else { if ($this->radix->archive && !$this->radix->getValue('archive_full_images')) { return null; } else { $image = $this->media->media; } } if ($download === true && $this->preferences->get('foolfuuka.boards.media_download_url')) { return $this->preferences->get('foolfuuka.boards.media_download_url') . '/' . $this->radix->shortname . '/' . ($thumbnail ? 'thumb' : 'image') . '/' . substr($image, 0, 4) . '/' . substr($image, 4, 2) . '/' . $image; } $cdn = ''; if ($request->isSecure() && $this->preferences->get('foolfuuka.boards.media_balancers_https')) { $cdn = $this->preferences->get('foolfuuka.boards.media_balancers_https'); } elseif ($this->preferences->get('foolfuuka.boards.media_balancers')) { $cdn = $this->preferences->get('foolfuuka.boards.media_balancers'); } $cdn = array_filter(preg_split('/\\r\\n|\\r|\\n/', $cdn)); if (!empty($cdn)) { return $cdn[$this->media->media_id % count($cdn)] . '/' . $this->radix->shortname . '/' . ($thumbnail ? 'thumb' : 'image') . '/' . substr($image, 0, 4) . '/' . substr($image, 4, 2) . '/' . $image; } return $this->preferences->get('foolfuuka.boards.url') . '/' . $this->radix->shortname . '/' . ($thumbnail ? 'thumb' : 'image') . '/' . substr($image, 0, 4) . '/' . substr($image, 4, 2) . '/' . $image; }
/** * TOKEN ENDPOINT * Token endpoint - used to exchange an authorization grant for an access token. * @param Request $request * @return string */ public function tokenAction(Request $request) { if (!$request->isSecure()) { throw new HttpException(400, 'This route requires the use of the https scheme', null, ['content-type' => 'application/json']); } $this->oAuth2Adapter->grantAccessToken($request); ob_flush(); flush(); // As OAuth2 library already outputs response content, we need to send an empty // response to avoid breaking silex controller return ''; }
/** * 绑定request到routing的context * @param Request $request * @param RequestContext $context * @return RequestContext */ protected function bindRequestToContext(Request $request, RequestContext $context) { $context->setBaseUrl($request->getBaseUrl()); $context->setPathInfo($request->getPathInfo()); $context->setMethod($request->getMethod()); $context->setHost($request->getHost()); $context->setScheme($request->getScheme()); $context->setHttpPort($request->getPort()); $context->setHttpPort($request->isSecure() ? null : $request->getPort()); $context->setHttpsPort($request->isSecure() ? $request->getPort() : null); $context->setQueryString($request->server->get('QUERY_STRING', '')); return $context; }
public function testOverrideGlobals() { set_error_handler(array($this, "deprecationErrorHandler")); $request = new Request(); $request->initialize(array('foo' => 'bar')); // as the Request::overrideGlobals really work, it erase $_SERVER, so we must backup it $server = $_SERVER; $request->overrideGlobals(); $this->assertEquals(array('foo' => 'bar'), $_GET); $request->initialize(array(), array('foo' => 'bar')); $request->overrideGlobals(); $this->assertEquals(array('foo' => 'bar'), $_POST); $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); $this->startTrustingProxyData(); $request->headers->set('X_FORWARDED_PROTO', 'https'); Request::setTrustedProxies(array('1.1.1.1')); $this->assertTrue($request->isSecure()); Request::setTrustedProxies(array()); $request->overrideGlobals(); $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); // restore initial $_SERVER array $_SERVER = $server; restore_error_handler(); }
/** * Creates a factory using incoming request. * * @param Request $request Incoming request. * @return CookieFactory */ public static function fromRequest(Request $request) { return new self($request->getBasePath(), $request->getHost(), $request->isSecure()); }
public function isSecure() { return $this->request->isSecure(); }
public function listAction(Request $request) { $result = array(); // if ($appConfig instanceof ApplicationConfiguration) { // if ($appConfig->allowGroupEditing) { // $groupRepository = $this->container->getDoctrine()->getManager()->getRepository(Group::CN()); // $groups = $groupRepository->findAll(); // // foreach($groups as $group) { // // $result[] = array( // 'id' => $group->getId(), // 'avatar' => null, // 'name' => '[' . $group->getName() . ']', // 'group' => $this->groupToDummyId($group) // ); // } //} //} $users = $this->container->getDoctrine()->getManager()->getRepository(User::CN())->findAll(); /* @var $user User */ foreach ($users as $user) { if (is_null($user->getGroup())) { $this->container->getLogger()->debug('User has no group: ' . $user->getId()); continue; } $result[] = array('id' => $user->getId(), 'avatar' => $user->getGravatarUrl(48, $request->isSecure() ? 'https' : 'http'), 'name' => $user->getName(), 'group' => $this->groupToDummyId($user->getGroup())); } return new SupraJsonResponse($result); }
/** * Log a warning and debug notice if this route is not HTTPS. * * @param Application $app * @param Request $request * * @return bool */ private function assertSecure(Application $app, Request $request) { if ($request->isSecure()) { return true; } $msg = sprintf("Login route '%s' is not being served over HTTPS. This is insecure and vulnerable!", $request->getPathInfo()); $app['logger.system']->critical(sprintf('[Members][Controller]: %s', $msg), ['event' => 'extensions']); $this->getMembersFeedback()->debug($msg); return false; }
public function testForwardedSecure() { $request = new Request(); $request->headers->set('X-Forwarded-Proto', 'https'); $request->headers->set('X-Forwarded-Port', 443); $this->startTrustingProxyData(); $this->assertTrue($request->isSecure()); $this->assertEquals(443, $request->getPort()); $this->stopTrustingProxyData(); }
/** * Returns either the HTTP or SSL version of an asset package. * * @param Request $request The current request * @param string $httpId The id for the package to use when the current request is HTTP * @param string $sslId The id for the package to use when the current request is SSL * * @return PackageInterface The package */ public function getPackage(Request $request, $httpId, $sslId) { return $this->container->get($request->isSecure() ? $sslId : $httpId); }
public function testOverrideGlobals() { $request = new Request(); $request->initialize(array('foo' => 'bar')); // as the Request::overrideGlobals really work, it erase $_SERVER, so we must backup it $server = $_SERVER; $request->overrideGlobals(); $this->assertEquals(array('foo' => 'bar'), $_GET); $request->initialize(array(), array('foo' => 'bar')); $request->overrideGlobals(); $this->assertEquals(array('foo' => 'bar'), $_POST); $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); $request->headers->set('X_FORWARDED_PROTO', 'https'); Request::setTrustedProxies(array('1.1.1.1')); $this->assertFalse($request->isSecure()); $request->server->set('REMOTE_ADDR', '1.1.1.1'); $this->assertTrue($request->isSecure()); Request::setTrustedProxies(array()); $request->overrideGlobals(); $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); $request->headers->set('CONTENT_TYPE', 'multipart/form-data'); $request->headers->set('CONTENT_LENGTH', 12345); $request->overrideGlobals(); $this->assertArrayHasKey('CONTENT_TYPE', $_SERVER); $this->assertArrayHasKey('CONTENT_LENGTH', $_SERVER); $request->initialize(array('foo' => 'bar', 'baz' => 'foo')); $request->query->remove('baz'); $request->overrideGlobals(); $this->assertEquals(array('foo' => 'bar'), $_GET); $this->assertEquals('foo=bar', $_SERVER['QUERY_STRING']); $this->assertEquals('foo=bar', $request->server->get('QUERY_STRING')); // restore initial $_SERVER array $_SERVER = $server; }
/** * Prepare some data for chat for operator * * @param UrlGeneratorInterface $url_generator A URL generator object. * @param Request $request The current request. * @param Thread $thread thread object. * @param array $operator Operator's data. * @return array Array of chat view data */ function setup_chatview_for_operator(UrlGeneratorInterface $url_generator, Request $request, Thread $thread, $operator) { $data = setup_chatview($thread); // Set operator info $data['chat']['user'] = array('name' => htmlspecialchars(get_user_name($thread->userName, $thread->remote, $thread->userId)), 'canPost' => (bool) ($thread->agentId == $operator['operatorid']), 'isAgent' => true); // Set SSL link if (Settings::get('enablessl') == "1" && !$request->isSecure()) { $data['chat']['links']['ssl'] = $url_generator->generateSecure('chat_operator', array('thread_id' => $thread->id, 'token' => $thread->lastToken), UrlGeneratorInterface::ABSOLUTE_URL); } // Set chat link $data['chat']['links']['chat'] = $url_generator->generate('chat_operator', array('thread_id' => $thread->id, 'token' => $thread->lastToken), UrlGeneratorInterface::ABSOLUTE_URL); // Set history window params $data['chat']['links']['history'] = $url_generator->generate('history_user', array('user_id' => $thread->userId)); // Set tracking params if (Settings::get('enabletracking')) { $visitor = track_get_visitor_by_thread_id($thread->id); $data['chat']['links']['tracked'] = $url_generator->generate('history_user_track', array('visitor' => $visitor['visitorid'])); } // Check if agent can post messages if ($thread->agentId == $operator['operatorid']) { // Get predefined answers $canned_messages = load_canned_messages($thread->locale, 0); if ($thread->groupId) { $canned_messages = array_merge(load_canned_messages($thread->locale, $thread->groupId), $canned_messages); } $predefined_answers = array(); foreach ($canned_messages as $answer) { $predefined_answers[] = array('short' => htmlspecialchars($answer['vctitle'] ? $answer['vctitle'] : cut_string($answer['vcvalue'], 97, '...')), 'full' => $answer['vcvalue']); } $data['chat']['messageForm']['predefinedAnswers'] = $predefined_answers; } // Set link to user redirection page $data['chat']['links']['redirect'] = $url_generator->generate('chat_operator_redirection_links', array('thread_id' => $thread->id, 'token' => $thread->lastToken)); return $data; }