<commit_before><?php
/*
 * Copyright 2010 CosmoCode GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

require('PalavaException.php');
require('PalavaArgumentsException.php');
require('PalavaConnectionException.php');
require('PalavaExecutionException.php');
require('PalavaParseException.php');
require('PalavaSession.php');
require('LazyPalavaSession.php');
require('EagerPalavaSession.php');
require('NativePalavaSession.php');
require('PalavaStatistics.php');

/**
 * Palava IPC PHP JSON Connector Client implementation.
 *
 * @author <NAME>
 */
class Palava {

	// used to read response from the server
	public static $BUFFER_CHUNK_SIZE = 8192;

	// cookie name for the session id cookie
	public static $SESSION_KEY = 'psessid';
    public static $COOKIE_PATH = '/';

	// protocol constants
	private static $PROTOCOL_KEY = "palava2/1.0";

	private static $PKEY_PROTOCOL = "protocol";
	private static $PKEY_SESSION = "session";
	private static $PKEY_COMMAND = "command";
	private static $PKEY_ARGUMENTS = "arguments";
	private static $PKEY_META = "meta";
    private static $PKEY_RESULT = "result";
    private static $PKEY_EXCEPTION = "exception";

	// will be configured
	private $host;
	private $port;

    // session data
    private $sessionKey;
    private $cookie_path;
    private $sessionId;

	// the socket of our connection
	private $socket = NULL;
	private $timeout = NULL;

	/**
	 * The current palava session or null if the session class was not used.
	 * 
	 * @var PalavaSession
	 */
	private $session = NULL;

	public function __construct($host, $port, $session_id = null) {
		$this->host = $host;
		$this->port = $port;
		$this->sessionKey = Palava::$SESSION_KEY;
        $this->cookie_path = Palava::$COOKIE_PATH;

        if (is_null($session_id)) {
		    if (isset($_COOKIE[$this->sessionKey])) {
			    $this->sessionId = $_COOKIE[$this->sessionKey];
		    }
            if (isset($_GET[$this->sessionKey])) {
                $this->sessionId = $_GET[$this->sessionKey];
            }
            if (isset($_POST[$this->sessionKey])) {
                $this->sessionId = $_POST[$this->sessionKey];
            }
        } else {
            $this->sessionId = $session_id;
        }
	}

    public function getSessionKey() {
		return $this->sessionKey;
	}

	public function getSessionId() {
		return $this->sessionId;
	}

    public function setSessionId($session_id) {
        $this->sessionId = $session_id;
    }

	/**
	 * Provides an instance of PalavaSession to easily operate with session
	 * data. Repeated calls to this function will return the session
	 * instance create at the first call. If lazy mode was choosen,
	 * changes to the session will be pushed back to the remote session
	 * right before this palava instance disconnects. 
	 * 
	 * @param $mode the session operation mode, please refer to PalavaSession
	 *        for more details, defaults to lazy
	 * @param $namespace the session namespace being used
	 */
	public function getSession($mode = PalavaSession::LAZY, $namespace = NULL) {
		if ($this->session === NULL) {
		    switch ($mode) {
		        case PalavaSession::LAZY: {
		            $this->session = new LazyPalavaSession($this, $namespace);
		            break;
		        }
		        case PalavaSession::EAGER: {
		            $this->session = new EagerPalavaSession($this, $namespace);
		            break;
		        }
                case PalavaSession::NATIVE: {
		            $this->session = new NativePalavaSession($this, $namespace);
		            break;
		        }
		        default: {
		            throw new PalavaSession("Unknown mode $mode");
		        }
		    }
		}
		return $this->session;
	}
	
	/**
	 * Uses the session returned by $this->getSession(..) and uses it at
	 * $_SESSION by calling $this->session->useGlobally().
	 * 
     * @param $mode the session operation mode, please refer to PalavaSession
     *        for more details, defaults to lazy
	 */
	public function useSessionGlobally($mode = PalavaSession::LAZY, $namespace = NULL) {
		$this->getSession($mode, $namespace)->useGlobally();
	}
	
	public function connect($timeout = null) {
		if (is_null($timeout)) {
			$timeout = ini_get("default_socket_timeout");
		}
		// connect!
		$this->socket = @fsockopen($this->host, $this->port, $errno, $errmsg, $timeout);
		if (!$this->socket) {
			throw new PalavaConnectionException("cannot connect to backend ".$this->host.":".$this->port." within $timeout seconds: [$errno] $errmsg");
		}
	}
	
	public function connectLazily($timeout = NULL) {
        $this->timeout = $timeout === NULL ? ini_get("default_socket_timeout") : $timeout;
	}

	public function call($command, $arguments = null) {
		// not yet connected?
		if ($this->socket === NULL) {
			if ($this->timeout === NULL) {
				throw new PalavaException('Neither connect() nor connectLazily() has been called ');
			}
			$this->connect($this->timeout);
		}
		
		// test input
		if (!is_string($command)) {
			throw new PalavaArgumentsException("invalid command name");
		}
		if (is_null($arguments) or empty($arguments)) {
            $arguments = new stdclass();
		} else if (!is_array($arguments) && !($arguments instanceof stdclass)) {
			throw new PalavaArgumentsException("arguments invalid; array expected");
		}

        // request uri
        if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') {
            $request_uri = 'https://';
        } else {
            $request_uri = 'http://';
        }
        $request_uri .= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];

		// build request
		$request = array();
		$request[Palava::$PKEY_PROTOCOL] = Palava::$PROTOCOL_KEY;
		$request[Palava::$PKEY_SESSION] = $this->sessionId;
		$request[Palava::$PKEY_COMMAND] = $command;
		$request[Palava::$PKEY_META] = array(
            'identifier' => $_SERVER['REMOTE_ADDR'],
            'request_uri' => $request_uri
        );
		$request[Palava::$PKEY_ARGUMENTS] = $arguments;

		// send it
		$json = json_encode($request);

        $call_start = microtime(true);
		if (!@fwrite($this->socket, $json)) {
			throw new PalavaConnectionException("cannot send request");
		}
		if (!@fflush($this->socket)) {
			throw new PalavaConnectionException("cannot flush request");
		}

		// read the response
		$buffer = '';
		$json_pointer = 0;
		$json_counter = 0;
		$json_in_string = false;
		$json_is_escaped = false;
		$json_completed = false;
		while (!feof($this->socket)) {
            $buffer .= @fread($this->socket, self::$BUFFER_CHUNK_SIZE);
			while ($json_pointer < strlen($buffer)) {
				$current = substr($buffer, $json_pointer, 1);
				if (!$json_in_string) {
					if ($current == '"') {
						$json_in_string = true;<commit_msg>use X_FORWARDED_FOR and X_REAL_IP headers for user identification is set<commit_after><?php
/*
 * Copyright 2010 CosmoCode GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

require('PalavaException.php');
require('PalavaArgumentsException.php');
require('PalavaConnectionException.php');
require('PalavaExecutionException.php');
require('PalavaParseException.php');
require('PalavaSession.php');
require('LazyPalavaSession.php');
require('EagerPalavaSession.php');
require('NativePalavaSession.php');
require('PalavaStatistics.php');

/**
 * Palava IPC PHP JSON Connector Client implementation.
 *
 * @author <NAME>
 */
class Palava {

	// used to read response from the server
	public static $BUFFER_CHUNK_SIZE = 8192;

	// cookie name for the session id cookie
	public static $SESSION_KEY = 'psessid';
    public static $COOKIE_PATH = '/';

	// protocol constants
	private static $PROTOCOL_KEY = "palava2/1.0";

	private static $PKEY_PROTOCOL = "protocol";
	private static $PKEY_SESSION = "session";
	private static $PKEY_COMMAND = "command";
	private static $PKEY_ARGUMENTS = "arguments";
	private static $PKEY_META = "meta";
    private static $PKEY_RESULT = "result";
    private static $PKEY_EXCEPTION = "exception";

	// will be configured
	private $host;
	private $port;

    // session data
    private $sessionKey;
    private $cookie_path;
    private $sessionId;

	// the socket of our connection
	private $socket = NULL;
	private $timeout = NULL;

	/**
	 * The current palava session or null if the session class was not used.
	 * 
	 * @var PalavaSession
	 */
	private $session = NULL;

	public function __construct($host, $port, $session_id = null) {
		$this->host = $host;
		$this->port = $port;
		$this->sessionKey = Palava::$SESSION_KEY;
        $this->cookie_path = Palava::$COOKIE_PATH;

        if (is_null($session_id)) {
		    if (isset($_COOKIE[$this->sessionKey])) {
			    $this->sessionId = $_COOKIE[$this->sessionKey];
		    }
            if (isset($_GET[$this->sessionKey])) {
                $this->sessionId = $_GET[$this->sessionKey];
            }
            if (isset($_POST[$this->sessionKey])) {
                $this->sessionId = $_POST[$this->sessionKey];
            }
        } else {
            $this->sessionId = $session_id;
        }
	}

    public function getSessionKey() {
		return $this->sessionKey;
	}

	public function getSessionId() {
		return $this->sessionId;
	}

    public function setSessionId($session_id) {
        $this->sessionId = $session_id;
    }

	/**
	 * Provides an instance of PalavaSession to easily operate with session
	 * data. Repeated calls to this function will return the session
	 * instance create at the first call. If lazy mode was choosen,
	 * changes to the session will be pushed back to the remote session
	 * right before this palava instance disconnects. 
	 * 
	 * @param $mode the session operation mode, please refer to PalavaSession
	 *        for more details, defaults to lazy
	 * @param $namespace the session namespace being used
	 */
	public function getSession($mode = PalavaSession::LAZY, $namespace = NULL) {
		if ($this->session === NULL) {
		    switch ($mode) {
		        case PalavaSession::LAZY: {
		            $this->session = new LazyPalavaSession($this, $namespace);
		            break;
		        }
		        case PalavaSession::EAGER: {
		            $this->session = new EagerPalavaSession($this, $namespace);
		            break;
		        }
                case PalavaSession::NATIVE: {
		            $this->session = new NativePalavaSession($this, $namespace);
		            break;
		        }
		        default: {
		            throw new PalavaSession("Unknown mode $mode");
		        }
		    }
		}
		return $this->session;
	}
	
	/**
	 * Uses the session returned by $this->getSession(..) and uses it at
	 * $_SESSION by calling $this->session->useGlobally().
	 * 
     * @param $mode the session operation mode, please refer to PalavaSession
     *        for more details, defaults to lazy
	 */
	public function useSessionGlobally($mode = PalavaSession::LAZY, $namespace = NULL) {
		$this->getSession($mode, $namespace)->useGlobally();
	}
	
	public function connect($timeout = null) {
		if (is_null($timeout)) {
			$timeout = ini_get("default_socket_timeout");
		}
		// connect!
		$this->socket = @fsockopen($this->host, $this->port, $errno, $errmsg, $timeout);
		if (!$this->socket) {
			throw new PalavaConnectionException("cannot connect to backend ".$this->host.":".$this->port." within $timeout seconds: [$errno] $errmsg");
		}
	}
	
	public function connectLazily($timeout = NULL) {
        $this->timeout = $timeout === NULL ? ini_get("default_socket_timeout") : $timeout;
	}

    private function getUserIp() {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else if (isset($_SERVER['HTTP_X_REAL_IP']) && !empty($_SERVER['HTTP_X_REAL_IP'])) {
            return $_SERVER['HTTP_X_REAL_IP'];
        } else {
            return $_SERVER['REMOTE_ADDR'];
        }
    }

	public function call($command, $arguments = null) {
		// not yet connected?
		if ($this->socket === NULL) {
			if ($this->timeout === NULL) {
				throw new PalavaException('Neither connect() nor connectLazily() has been called ');
			}
			$this->connect($this->timeout);
		}
		
		// test input
		if (!is_string($command)) {
			throw new PalavaArgumentsException("invalid command name");
		}
		if (is_null($arguments) or empty($arguments)) {
            $arguments = new stdclass();
		} else if (!is_array($arguments) && !($arguments instanceof stdclass)) {
			throw new PalavaArgumentsException("arguments invalid; array expected");
		}

        // request uri
        if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') {
            $request_uri = 'https://';
        } else {
            $request_uri = 'http://';
        }
        $request_uri .= $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];

		// build request
		$request = array();
		$request[Palava::$PKEY_PROTOCOL] = Palava::$PROTOCOL_KEY;
		$request[Palava::$PKEY_SESSION] = $this->sessionId;
		$request[Palava::$PKEY_COMMAND] = $command;
		$request[Palava::$PKEY_META] = array(
            'identifier' => $this->getUserIp(),
            'request_uri' => $request_uri
        );
		$request[Palava::$PKEY_ARGUMENTS] = $arguments;

		// send it
		$json = json_encode($request);

        $call_start = microtime(true);
		if (!@fwrite($this->socket, $json)) {
			throw new PalavaConnectionException("cannot send request");
		}
		if (!@fflush($this->socket)) {
			throw new PalavaConnectionException("cannot flush request");
		}

		// read the response
		$buffer = '';
		$json_pointer = 0;
		$json_counter = 0;
		$json_in_string = false;
		$json_is_escaped = false;
		$json_completed = false;
		while (!feof($this->socket)) {
            $buffer .= @fread($this->socket, self::$BUFFER_CHUNK_SIZE);
			while ($json_pointer < strlen($buffer)) {
				$current = substr($buffer, $json_pointer, 1);
				if (!$json_in_string) {
					if ($current == '"') {
						$json_in_string = true;
{'fraction_non_alphanumeric': 0.13668098818474758, 'fraction_numerical': 0.0024167561761546724, 'mean_word_length': 3.2022566995768686, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 96, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '507983', 'n_tokens_mistral': 4757, 'n_tokens_neox': 4386, 'n_words': 1179}