/core/model/modx/modconnectorresponse.class.php
PHP | 278 lines | 167 code | 14 blank | 97 comment | 49 complexity | f49a23070dcf4b945c51df92acae3200 MD5 | raw file
Possible License(s): GPL-2.0, Apache-2.0, BSD-3-Clause, LGPL-2.1
- <?php
- /*
- * This file is part of MODX Revolution.
- *
- * Copyright (c) MODX, LLC. All Rights Reserved.
- *
- * For complete copyright and license information, see the COPYRIGHT and LICENSE
- * files found in the top-level directory of this distribution.
- */
- require_once MODX_CORE_PATH . 'model/modx/modresponse.class.php';
- /**
- * Encapsulates an HTTP response from the MODX manager.
- *
- * {@inheritdoc}
- *
- * @package modx
- * @extends modResponse
- */
- class modConnectorResponse extends modResponse {
- /**
- * The base location of the processors called by the connectors.
- *
- * @var string
- * @access private
- */
- protected $_directory;
- public $responseCode = 200;
- protected $_responseCodes = array(
- 100 => 'Continue',
- 101 => 'Switching Protocols',
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 303 => 'See Other',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 306 => '(Unused)',
- 307 => 'Temporary Redirect',
- 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',
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported'
- );
- /**
- * Creates a modConnectorResponse object.
- *
- * {@inheritdoc}
- */
- function __construct(modX & $modx) {
- parent :: __construct($modx);
- $this->setDirectory();
- }
- /**
- * Overrides modResponse::outputContent to provide connector-specific
- * processing.
- *
- * {@inheritdoc}
- */
- public function outputContent(array $options = array()) {
- /* variable pointer for easier access */
- $modx =& $this->modx;
- /* backwards compat */
- $error =& $this->modx->error;
- /* prevent browsing of subdirectories for security */
- $target = preg_replace('/[\.]{2,}/', '', htmlspecialchars($options['action']));
- $siteId = $this->modx->user->getUserToken($this->modx->context->get('key'));
- $isLogin = $target == 'login' || $target == 'security/login';
- /* Block the user if there's no user token for the current context, and permissions are in fact required */
- if (empty($siteId) && (!defined('MODX_REQP') || MODX_REQP === TRUE)) {
- $this->responseCode = 401;
- $this->body = $modx->error->failure($modx->lexicon('access_denied'),array('code' => 401));
- }
- /* Make sure we've got a token */
- elseif (!$isLogin && !isset($_SERVER['HTTP_MODAUTH']) && (!isset($_REQUEST['HTTP_MODAUTH']) || empty($_REQUEST['HTTP_MODAUTH']))) {
- $this->responseCode = 401;
- $this->body = $modx->error->failure($modx->lexicon('access_denied'),array('code' => 401));
- }
- /* If the token was passed as a request header (like in the manager), check if it's right */
- else if (!$isLogin && isset($_SERVER['HTTP_MODAUTH']) && $_SERVER['HTTP_MODAUTH'] != $siteId) {
- $this->responseCode = 401;
- $this->body = $modx->error->failure($modx->lexicon('access_denied'),array('code' => 401));
- }
- /* If the token was passed a request variable, check if it's right */
- else if (!$isLogin && isset($_REQUEST['HTTP_MODAUTH']) && $_REQUEST['HTTP_MODAUTH'] != $siteId) {
- $this->responseCode = 401;
- $this->body = $modx->error->failure($modx->lexicon('access_denied'), array('code' => 401));
- }
- /* verify the location and action */
- /*else if (!isset($options['location']) || !isset($options['action'])) {
- $this->responseCode = 404;
- $this->body = $this->modx->error->failure($modx->lexicon('action_err_ns'),array('code' => 404));
- }*/
- /* If we don't have an action, 404 out */
- else if (empty($options['action'])) {
- $this->responseCode = 404;
- $this->body = $this->modx->error->failure($modx->lexicon('action_err_ns'), array('code' => 404));
- }
- /* execute a processor and format the response */
- else {
- /* create scriptProperties array from HTTP GPC vars */
- if (!isset($_POST)) $_POST = array();
- if (!isset($_GET) || $isLogin) $_GET = array();
- $scriptProperties = array_merge($_GET,$_POST);
- if (isset($_FILES) && !empty($_FILES)) {
- $scriptProperties = array_merge($scriptProperties,$_FILES);
- }
- /* run processor */
- $this->response = $this->modx->runProcessor($target,$scriptProperties,$options);
- if (!$this->response) {
- $this->responseCode = 404;
- $this->body = $this->modx->error->failure($this->modx->lexicon('processor_err_nf',array(
- 'target' => $target,
- )));
- } else {
- $this->body = $this->response->getResponse();
- }
- }
- /* if files sent, this means that the browser needs it in text/plain,
- * so ignore text/json header type
- */
- if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
- header("Content-Type: application/json; charset=UTF-8");
- $message = 'OK';
- if (array_key_exists($this->responseCode,$this->_responseCodes)) {
- $message = $this->_responseCodes[$this->responseCode];
- }
- header('Status: '.$this->responseCode.' '.$message);
- header('Version: ' . $_SERVER['SERVER_PROTOCOL']);
- }
- if (is_array($this->header)) {
- foreach ($this->header as $header) header($header);
- }
- if (is_array($this->body)) {
- @session_write_close();
- $json = $this->modx->toJSON(array(
- 'success' => isset($this->body['success']) ? $this->body['success'] : 0,
- 'message' => isset($this->body['message']) ? $this->body['message'] : $this->modx->lexicon('error'),
- 'total' => (isset($this->body['total']) && $this->body['total'] > 0)
- ? intval($this->body['total'])
- : (isset($this->body['errors'])
- ? count($this->body['errors'])
- : 1),
- 'data' => isset($this->body['errors']) ? $this->body['errors'] : array(),
- 'object' => isset($this->body['object']) ? $this->body['object'] : array(),
- ));
- if (!empty($_GET['callback'])) {
- $json = $modx->stripTags($_GET['callback']) . '(' . $json . ')';
- }
- die($json);
- } else {
- @session_write_close();
- die($this->body);
- }
- }
- /**
- * Return arrays of objects (with count) converted to JSON.
- *
- * The JSON result includes two main elements, total and results. This format is used for list
- * results.
- *
- * @access public
- * @param array $array An array of data objects.
- * @param mixed $count The total number of objects. Used for pagination.
- * @return string The JSON output.
- */
- public function outputArray(array $array,$count = false) {
- if (!is_array($array)) return false;
- if ($count === false) { $count = count($array); }
- return '({"total":"'.$count.'","results":'.$this->modx->toJSON($array).'})';
- }
- /**
- * Set the physical location of the processor directory for the response handler.
- *
- * This allows for dynamic processor locations.
- *
- * @access public
- * @param string $dir The directory to set as the processors directory.
- */
- public function setDirectory($dir = '') {
- if ($dir == '') {
- $this->_directory = $this->modx->getOption('processors_path');
- } else {
- $this->_directory = $dir;
- }
- }
- /**
- * Converts PHP to JSON with JavaScript literals left in-tact.
- *
- * JSON does not allow JavaScript literals, but this function encodes certain identifiable
- * literals and decodes them back into literals after modX::toJSON() formats the data.
- *
- * @access public
- * @param mixed $data The PHP data to be converted.
- * @return string The extended JSON-encoded string.
- */
- public function toJSON($data) {
- if (is_array($data)) {
- array_walk_recursive($data, array(&$this, '_encodeLiterals'));
- }
- return $this->_decodeLiterals($this->modx->toJSON($data));
- }
- /**
- * Encodes certain JavaScript literal strings for later decoding.
- *
- * @access protected
- * @param mixed &$value A reference to the value to be encoded if it is identified as a literal.
- * @param integer|string $key The array key corresponding to the value.
- */
- protected function _encodeLiterals(&$value, $key) {
- if (is_string($value)) {
- /* properly handle common literal structures */
- if (strpos($value, 'function(') === 0
- || strpos($value, 'this.') === 0
- || strpos($value, 'new Function(') === 0
- || strpos($value, 'Ext.') === 0) {
- $value = '@@' . base64_encode($value) . '@@';
- }
- }
- }
- /**
- * Decodes strings encoded by _encodeLiterals to restore JavaScript literals.
- *
- * @access protected
- * @param string $string The JSON-encoded string with encoded literals.
- * @return string The JSON-encoded string with literals restored.
- */
- protected function _decodeLiterals($string) {
- $pattern = '/"@@(.*?)@@"/';
- $string = preg_replace_callback(
- $pattern,
- function ($matches) { return base64_decode($matches[1]); },
- $string
- );
- return $string;
- }
- }