<?php
/**
* @version	$Id: curl_helper.php 14000 2010-10-19 15:24:28Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class kCurlHelper extends kHelper {

		/**
		 * Connection to host
		 *
		 * @var resource
		 */
		var $connectionID = null;

		/**
		 * Pointer to opened log file
		 *
		 * @var resource
		 */
		var $logFilePointer = null;

		/**
		 * Responce waiting timeout
		 *
		 * @var int
		 */
		var $timeout = 90;

		/**
		 * Follow to url, if redirect received insted of document (only works when open_basedir and safe mode is off)
		 *
		 * @var bool
		 */
		var $followLocation = false;

		/**
		 * Last responce received by Curl
		 *
		 * @var string
		 */
		var $lastRespoce = '';

		/**
		 * Last error code
		 *
		 * @var int
		 */
		var $lastErrorCode = 0;

		/**
		 * Last error message
		 *
		 * @var string
		 */
		var $lastErrorMsg = '';

		/**
		 * Most recent HTTP responce code received
		 *
		 * @var int
		 */
		var $lastHTTPCode = 0;

		/**
		 * POST data to be sent using curl
		 *
		 * @var string
		 */
		var $postData = '';

		var $requestHeaders = Array ();

		var $responceHeaders = Array ();

		var $options = Array ();

		/**
		 * Indicates debug mode status
		 *
		 * @var bool
		 */
		var $debugMode = false;

		function kCurlHelper()
		{
			parent::kHelper();

			$this->debugMode = constOn('DBG_CURL');
		}

		/**
		 * Reset connection settings (not results) after connection was closed
		 *
		 */
		function _resetSettings()
		{
			$this->timeout = 90;
			$this->followLocation = false;
			$this->postData = '';
			$this->requestHeaders = Array ();
			$this->options = Array ();
		}

		function setOptions($options_hash)
		{
			$this->options = array_merge_recursive2($this->options, $options_hash);
		}

		function prepareOptions()
		{
			if ($this->followLocation && ((defined('SAFE_MODE') && SAFE_MODE) || ini_get('open_basedir'))) {
				// this won't work with such restrictions, so turn it off
				$this->followLocation = false;
			}

			$default_options = Array (
				// customizable options
				CURLOPT_FOLLOWLOCATION => $this->followLocation ? 1 : 0,
				CURLOPT_TIMEOUT => $this->timeout,

				// hardcoded options
				CURLOPT_RETURNTRANSFER => 1,
				CURLOPT_REFERER => PROTOCOL.SERVER_NAME,
				CURLOPT_USERAGENT => $_SERVER['HTTP_USER_AGENT'],
				
				// don't verify SSL certificates
				CURLOPT_SSL_VERIFYPEER => false,
				CURLOPT_HTTPHEADER => Array ('Expect:'),
			);

			if ($this->requestHeaders) {
				$default_options[CURLOPT_HTTPHEADER] = $this->prepareHeaders();
			}

			// if we have post data, then POST else use GET method instead
			if ($this->postData) {
				$default_options[CURLOPT_POST] = 1;
				$default_options[CURLOPT_POSTFIELDS] = $this->postData;
			}

//			$default_options[CURLOPT_HEADERFUNCTION] = Array(&$this, 'ParseHeader');

			$user_options = $this->options; // backup options, that user set directly
			$this->setOptions($default_options);
			$this->setOptions($user_options);
			$this->applyOptions();
		}

		function applyOptions()
		{
			foreach ($this->options as $option_name => $option_value) {
				curl_setopt($this->connectionID, $option_name, $option_value);
			}
		}

		function ParseHeader(&$ch, $header)
		{
			$this->responceHeaders[] = $header;
			return strlen($header);
		}

		/**
		 * Sets POST data for next query
		 *
		 * @param mixed $post_data Array or string
		 */
		function SetPostData($post_data)
		{
			if (is_array($post_data)) {
				$post_data = $this->Application->HttpQuery->_transformArrays($post_data);

				$params_str = '';
				foreach ($post_data as $key => $value) {
					$params_str .= $key.'='.urlencode($value).'&';
				}
				$post_data = $params_str;
			}

			$this->postData = $post_data;
		}

		function SetHeaders($headers)
		{
			$this->requestHeaders = array_merge_recursive2($this->requestHeaders, $headers);
		}

		function SetHeader($name, $value)
		{
			$this->requestHeaders[$name] = $value;
		}

		/**
		 * Returns compiled header to be used by curl
		 *
		 * @return Array
		 */
		function prepareHeaders()
		{
			$ret = Array ();
			foreach ($this->requestHeaders as $header_name => $header_value) {
				$ret[] = $header_name.': '.$header_value;
			}
			return $ret;
		}

		function Send($url, $close_connection = true, $log_status = null)
		{
			if (isset($log_status)) {
				// override debug mode setting
				$this->debugMode = $log_status;
			}

			$this->connectionID = curl_init($url);

			if ($this->debugMode) {
				safeDefine('DBG_CURL_LOGFILE', '/curl.log');
				$this->logFilePointer = fopen(FULL_PATH.DBG_CURL_LOGFILE, 'a');

				$user_id = $this->Application->RecallVar('user_id');
				$data = $_SERVER['REMOTE_ADDR'] . ' - ['.adodb_date('D M d H:i:s Y').'] ' . $_SERVER['REQUEST_URI'] . '; user_id: '.$user_id.'; sid: '.$this->Application->GetSID();
				fwrite($this->logFilePointer, "\n\n" . str_repeat('=', strlen($data)) . "\n");
				fwrite($this->logFilePointer, $data);
				fwrite($this->logFilePointer, "\n" . str_repeat('=', strlen($data)) . "\n");

				curl_setopt($this->connectionID, CURLOPT_FILE, $this->logFilePointer);
				curl_setopt($this->connectionID, CURLOPT_VERBOSE, true);
				curl_setopt($this->connectionID, CURLOPT_STDERR, $this->logFilePointer);
				//curl_setopt($this->connectionID, CURLOPT_WRITEHEADER, $this->logFilePointer);
			}

			$this->responceHeaders = Array ();

			$this->prepareOptions();
			$this->lastRespoce = curl_exec($this->connectionID);

			$this->Finalize($close_connection);

			return $this->lastRespoce;
		}

		/**
		 * Returns various info about request made
		 *
		 * @param int $info_type
		 * @return mixed
		 *
		 * @see http://www.php.net/manual/ru/function.curl-getinfo.php
		 */
		function getInfo($info_type)
		{
			return curl_getinfo($this->connectionID, $info_type);
		}

		function Finalize($close_connection = true)
		{
			$this->lastErrorCode = curl_errno($this->connectionID);
			$this->lastErrorMsg = curl_error($this->connectionID);
			$this->lastHTTPCode = curl_getinfo($this->connectionID, CURLINFO_HTTP_CODE);

			if ($close_connection) {
				$this->CloseConnection();
			}

			$this->_resetSettings();
		}

		function CloseConnection()
		{
			curl_close($this->connectionID);

			if ($this->debugMode) {
				// only close log after curl resource has been terminated
				fwrite($this->logFilePointer, "\n" . 'LastHTTPCode: ' . $this->lastHTTPCode . '; LastError: #' . $this->lastErrorCode . ' (' . $this->lastErrorMsg . ')' . "\n");
				fwrite($this->logFilePointer, 'Respoce:' . "\n" . $this->lastRespoce);
				fclose($this->logFilePointer);
			}

			// restore debug mode setting
			$this->debugMode = constOn('DBG_CURL');
		}
	}