Ctrl K
ComunidadGuías…

json.php

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<?php
/**
 * EGroupware - general JSON handler for EGroupware
 *
 * @link http://www.egroupware.org
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
 * @package api
 * @subpackage ajax
 * @author Andreas Stoeckel <as@stylite.de>
 */

use EGroupware\Api;
use EGroupware\Api\Egw;
use EGroupware\Api\Json;

/**
 * callback if the session-check fails, redirects to login.php, if no valid basic auth credentials given
 *
 * @param array &$anon_account anon account_info with keys 'login', 'passwd' and optional 'passwd_type'
 * @return boolean|string true if we allow anon access and anon_account is set, a sessionid or false otherwise
 */
function login_redirect(&$anon_account)
{
	// allow to make json calls via basic auth
	if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW']) &&
		($session_id = Api\Header\Authenticate::autocreate_session_callback($anon_account)))
	{
		return $session_id;
	}
	Json\Request::isJSONRequest(true);	// because Api\Json\Request::parseRequest() is not (yet) called
	$response = Json\Response::get();
	$response->apply('framework.callOnLogout');
	$response->redirect($GLOBALS['egw_info']['server']['webserver_url'].'/login.php?cd=10', true);

	// under PHP 8 the destructor is called to late and the response is not send
	$GLOBALS['egw']->__destruct();
	exit();
}

/**
 * Exception handler for xajax, return the message (and trace, if enabled) as alert() to the user
 *
 * Does NOT return!
 *
 * @param Exception|Error $e
 */
function ajax_exception_handler($e)
{
	// handle redirects without logging
	if (is_a($e, 'EGroupware\\Api\\Exception\\Redirect'))
	{
		Egw::redirect($e->url, $e->app);
	}
	// logging all exceptions to the error_log
	$message = null;
	if (function_exists('_egw_log_exception'))
	{
		_egw_log_exception($e,$message);
	}
	$response = Json\Response::get();
	$message .= ($message ? "\n\n" : '').$e->getMessage();

	$message .= "\n\n".$e->getFile().' ('.$e->getLine().')';
	// only show trace (incl. function arguments) if explicitly enabled, eg. on a development system
	if ($GLOBALS['egw_info']['server']['exception_show_trace'])
	{
		$message .= "\n\n".$e->getTraceAsString();
	}
	$response->message($message, 'error');

	// under PHP 8 the destructor is called to late and the response is not send
	$GLOBALS['egw']->__destruct();
	exit;
}

// set our own exception handler, to not get the html from eGW's default one
set_exception_handler('ajax_exception_handler');

try {
	if (!isset($_GET['menuaction']))
	{
		throw new InvalidArgumentException('Missing menuaction GET parameter', 998);
	}
	if (strpos($_GET['menuaction'],'::') !== false && strpos($_GET['menuaction'],'.') === false)	// static method name app_something::method
	{
		@list($className,$functionName,$handler) = explode('::',$_GET['menuaction'])+[2 => null];

		if (substr($className, 0, 11) == 'EGroupware\\')
		{
			list(,$appName) = explode('\\', strtolower($className));
		}
		else
		{
			list($appName) = explode('_',$className);
		}
	}
	else
	{
		@list($appName, $className, $functionName, $handler) = explode('.', $_GET['menuaction'])+[null, null, null, null];
	}
	//error_log("json.php: appName=$appName, className=$className, functionName=$functionName, handler=$handler");

	$GLOBALS['egw_info'] = array(
		'flags' => array(
			'currentapp'			=> $appName,
			'noheader'		=> True,
			'disable_Template_class'	=> True,
			'autocreate_session_callback' => 'login_redirect',
			'no_exception_handler' => true,	// we already installed our own
			// only log ajax requests which represent former GET requests or submits
			// cuts down updates to egw_access_log table
			'no_dla_update' => !preg_match('/(Etemplate::ajax_process_content|\.jdots_framework\.ajax_exec\.template)/', $_GET['menuaction']),
		)
	);
	include_once('./header.inc.php');

	// Close the session as early as possible, so it does not block other concurrent json.php
	// requests carrying the same session cookie for their full duration (PHP's default session
	// locking otherwise serializes them). Anything written to the session-cache after this point
	// (Api\Cache::setSession()/getSession()/unsetSession()) is captured by Cache's closed-session
	// write buffer and re-applied by Cache::flush_session_writes(), registered below to run right
	// before the response is flushed to the client (Egw::__destruct()'s pre-close callback pass).
	Egw::on_shutdown([Api\Cache::class, 'flush_session_writes']);
	$GLOBALS['egw']->session->commit_session();

	//Create a new json handler
	$json = new Json\Request();

	// check if we have a real json request
	if (strpos($_SERVER['CONTENT_TYPE'], 'application/json') === 0)
	{
		$json->parseRequest($_GET['menuaction'], file_get_contents('php://input'));
	}
	// json_data is only accepted via POST now (GET/$_REQUEST no longer read), except this one
	// read-only, side-effect-free call, which deliberately uses GET so browsers can revalidate
	// it via ETag/304 (see Framework::ajax_get_preference()).
	elseif ($className === 'EGroupware\\Api\\Framework' && $functionName === 'ajax_get_preference')
	{
		$json->parseRequest($_GET['menuaction'], $_GET['json_data'] ?? '');
	}
	else
	{
		// fail loud, not silently, if json_data still arrives via GET somewhere we missed
		if (isset($_GET['json_data']))
		{
			error_log('json.php: rejected json_data sent via GET from IP '.$_SERVER['REMOTE_ADDR'].
				' to '.$_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI']);
			throw new InvalidArgumentException('json_data must be sent via POST, not GET', 997);
		}
		$json->parseRequest($_GET['menuaction'], $_POST['json_data'] ?? '');
	}
	Json\Response::get();

	// run egw destructor now explicit, in case a (notification) email is send via Egw::on_shutdown(),
	// as stream-wrappers used by Horde Smtp fail when PHP is already in destruction
	$GLOBALS['egw']->__destruct();
}
// missing menuaction GET parameter or request:parameters object or unparsable JSON
catch (\InvalidArgumentException $e) {
	if (isset($json)) $json->isJSONRequest(false);	// no regular json request processing

	// give a proper HTTP status 400 Bad Request with some JSON payload explaining the problem
	http_response_code(400);
	header('Content-Type: application/json');
	echo json_encode(array('error' => $e->getMessage(), 'errno' => $e->getCode()));
}
// other exceptions are handled by our ajax_exception_handler sending them back as alerts to client-side