Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1101897
curl_helper.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Aug 17, 7:34 AM
Size
13 KB
Mime Type
text/x-php
Expires
Tue, Aug 19, 7:34 AM (11 h, 20 m)
Engine
blob
Format
Raw Data
Handle
713736
Attached To
rINP In-Portal
curl_helper.php
View Options
<?php
/**
* @version $Id: curl_helper.php 16752 2022-11-09 15:56:04Z 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
{
const
REQUEST_METHOD_GET
=
1
;
const
REQUEST_METHOD_POST
=
2
;
/**
* ID of database record of currently active curl request
*
* @var int
* @access protected
*/
protected
$logId
=
0
;
/**
* Connection to host
*
* @var resource
* @access protected
*/
protected
$connectionID
=
NULL
;
/**
* Response waiting timeout in seconds
*
* @var int
* @access public
*/
public
$timeout
=
90
;
/**
* Follow to url, if redirect received instead of document (only works when open_basedir and safe mode is off)
*
* @var bool
* @access public
*/
public
$followLocation
=
false
;
/**
* Last response received by Curl
*
* @var string
* @access public
*/
public
$lastResponse
=
''
;
/**
* Last error code
*
* @var int
* @access public
*/
public
$lastErrorCode
=
0
;
/**
* Last error message
*
* @var string
* @access public
*/
public
$lastErrorMsg
=
''
;
/**
* Most recent HTTP response code received
*
* @var int
* @access public
*/
public
$lastHTTPCode
=
0
;
/**
* Count of intermediate redirects performed to get actual content
*
* @var int
* @access protected
*/
protected
$lastRedirectCount
=
0
;
/**
* Default request method
*
* @var int
* @access protected
*/
protected
$requestMethod
=
self
::
REQUEST_METHOD_GET
;
/**
* Data to be sent using curl
*
* @var string
* @access protected
*/
protected
$requestData
=
''
;
/**
* Request headers (associative array)
*
* @var Array
* @access protected
*/
protected
$requestHeaders
=
Array
();
/**
* Response headers
*
* @var Array
* @access protected
*/
protected
$responseHeaders
=
Array
();
/**
* CURL options
*
* @var Array
* @access protected
*/
protected
$options
=
Array
();
/**
* Indicates debug mode status
*
* @var bool
* @access public
*/
public
$debugMode
=
false
;
/**
* Creates an instance of kCurlHelper class
*/
public
function
__construct
()
{
parent
::
__construct
();
$this
->
debugMode
=
kUtil
::
constOn
(
'DBG_CURL'
);
}
/**
* Reset connection settings (not results) after connection was closed
*
* @access protected
*/
protected
function
_resetSettings
()
{
$this
->
timeout
=
90
;
$this
->
followLocation
=
false
;
$this
->
requestMethod
=
self
::
REQUEST_METHOD_GET
;
$this
->
requestData
=
''
;
$this
->
requestHeaders
=
Array
();
$this
->
responseHeaders
=
Array
();
$this
->
options
=
Array
();
}
/**
* Resets information in last* properties.
*
* @return void
*/
protected
function
resetLastInfo
()
{
$this
->
lastErrorCode
=
0
;
$this
->
lastErrorMsg
=
''
;
$this
->
lastHTTPCode
=
0
;
$this
->
lastRedirectCount
=
0
;
}
/**
* Sets CURL options (adds to options set before)
*
* @param Array $options_hash
* @access public
*/
public
function
setOptions
(
$options_hash
)
{
$this
->
options
=
kUtil
::
array_merge_recursive
(
$this
->
options
,
$options_hash
);
}
/**
* Combines user-defined and default options before setting them to CURL
*
* @access protected
*/
protected
function
prepareOptions
()
{
$default_options
=
Array
(
// customizable options
CURLOPT_TIMEOUT
=>
$this
->
timeout
,
// hardcoded options
CURLOPT_RETURNTRANSFER
=>
1
,
CURLOPT_REFERER
=>
PROTOCOL
.
SERVER_NAME
,
CURLOPT_MAXREDIRS
=>
5
,
// don't verify SSL certificates
CURLOPT_SSL_VERIFYPEER
=>
false
,
CURLOPT_SSL_VERIFYHOST
=>
false
,
// Prevents CURL from adding "Expect: 100-continue" header for POST requests.
CURLOPT_HTTPHEADER
=>
Array
(
'Expect:'
),
);
if
(
isset
(
$_SERVER
[
'HTTP_USER_AGENT'
])
)
{
$default_options
[
CURLOPT_USERAGENT
]
=
$_SERVER
[
'HTTP_USER_AGENT'
];
}
if
(
$this
->
requestHeaders
)
{
$default_options
[
CURLOPT_HTTPHEADER
]
=
$this
->
prepareHeaders
();
}
// if we have post data, then POST else use GET method instead
if
(
$this
->
requestMethod
==
self
::
REQUEST_METHOD_POST
)
{
$default_options
[
CURLOPT_POST
]
=
1
;
$default_options
[
CURLOPT_POSTFIELDS
]
=
$this
->
requestData
;
}
$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
();
}
/**
* Sets prepared options to CURL
*
* @access protected
*/
protected
function
applyOptions
()
{
foreach
(
$this
->
options
as
$option_name
=>
$option_value
)
{
curl_setopt
(
$this
->
connectionID
,
$option_name
,
$option_value
);
}
}
/**
* Parses headers from CURL request
*
* @param resource $ch
* @param string $header
* @return int
* @access protected
*/
protected
function
ParseHeader
(&
$ch
,
$header
)
{
$trimmed_header
=
rtrim
(
$header
);
if
(
$trimmed_header
)
{
$this
->
responseHeaders
[]
=
$trimmed_header
;
}
return
strlen
(
$header
);
}
/**
* Sets request data for next query
*
* @param mixed $data Array or string
*/
public
function
SetRequestData
(
$data
)
{
if
(
is_array
(
$data
)
)
{
$data
=
http_build_query
(
$data
);
}
$this
->
requestData
=
$data
;
}
/**
* Sets request data for next query and switches request method to POST
*
* @param mixed $data Array or string
* @access public
*/
public
function
SetPostData
(
$data
)
{
$this
->
requestMethod
=
self
::
REQUEST_METHOD_POST
;
$this
->
SetRequestData
(
$data
);
}
/**
* Sets request method to be used in next request
*
* @param int $request_method
*
* @throws InvalidArgumentException When invalid request method given.
*/
public
function
SetRequestMethod
(
$request_method
)
{
if
(
$request_method
!=
self
::
REQUEST_METHOD_GET
&&
$request_method
!=
self
::
REQUEST_METHOD_POST
)
{
throw
new
InvalidArgumentException
(
'Method "'
.
__METHOD__
.
'": Invalid $request_method parameter value'
);
return
;
}
$this
->
requestMethod
=
$request_method
;
}
/**
* Sets headers to be sent along with next query
*
* @param Array $headers
* @access public
*/
public
function
SetHeaders
(
$headers
)
{
$this
->
requestHeaders
=
array_merge
(
$this
->
requestHeaders
,
$headers
);
}
/**
* Returns compiled header to be used by curl
*
* @return Array
* @access protected
*/
protected
function
prepareHeaders
()
{
$ret
=
Array
();
foreach
(
$this
->
requestHeaders
as
$header_name
=>
$header_value
)
{
$ret
[]
=
is_numeric
(
$header_name
)
?
$header_value
:
$header_name
.
': '
.
$header_value
;
}
return
$ret
;
}
/**
* Performs CURL request and returns it's result
*
* @param string $url
* @param bool $close_connection
* @param bool $log_status
* @param string $log_message
* @return string
* @access public
*/
public
function
Send
(
$url
,
$close_connection
=
true
,
$log_status
=
NULL
,
$log_message
=
''
)
{
if
(
isset
(
$log_status
)
)
{
// override debug mode setting
$this
->
debugMode
=
$log_status
;
}
$request_url
=
$url
;
if
(
$this
->
requestMethod
==
self
::
REQUEST_METHOD_GET
&&
$this
->
requestData
)
{
$request_url
.=
(
strpos
(
$request_url
,
'?'
)
!==
false
?
'&'
:
'?'
)
.
$this
->
requestData
;
}
$this
->
connectionID
=
curl_init
(
$request_url
);
if
(
$this
->
debugMode
)
{
// collect page data
$page_data
=
Array
();
if
(
$_GET
)
{
$page_data
[]
=
'_GET:'
.
"
\n
"
.
print_r
(
$_GET
,
true
);
}
if
(
$_POST
)
{
$page_data
[]
=
'_POST:'
.
"
\n
"
.
print_r
(
$_POST
,
true
);
}
if
(
$_COOKIE
)
{
$page_data
[]
=
'_COOKIE:'
.
"
\n
"
.
print_r
(
$_COOKIE
,
true
);
}
// create log record
$fields_hash
=
Array
(
'Message'
=>
$log_message
,
'PageUrl'
=>
$_SERVER
[
'REQUEST_URI'
],
'RequestUrl'
=>
$url
,
'PortalUserId'
=>
$this
->
Application
->
RecallVar
(
'user_id'
),
'SessionKey'
=>
$this
->
Application
->
GetSID
(),
'IsAdmin'
=>
$this
->
Application
->
isAdminUser
?
1
:
0
,
'PageData'
=>
implode
(
"
\n
"
,
$page_data
),
'RequestData'
=>
$this
->
requestData
,
'RequestDate'
=>
adodb_mktime
(),
);
$this
->
Conn
->
doInsert
(
$fields_hash
,
TABLE_PREFIX
.
'CurlLog'
);
$this
->
logId
=
$this
->
Conn
->
getInsertID
();
}
$this
->
prepareOptions
();
$this
->
lastResponse
=
$this
->
_sendRequest
();
$this
->
Finalize
(
$close_connection
);
return
$this
->
lastResponse
;
}
/**
* Reads data from remote url
*
* @return string
* @access protected
*/
protected
function
_sendRequest
()
{
$this
->
resetLastInfo
();
curl_setopt
(
$this
->
connectionID
,
CURLOPT_RETURNTRANSFER
,
true
);
if
(
$this
->
followLocation
)
{
if
(
$this
->
followLocationLimited
()
)
{
return
$this
->
_followLocationManually
();
}
else
{
// no restrictions - let curl do automatic redirects
curl_setopt
(
$this
->
connectionID
,
CURLOPT_FOLLOWLOCATION
,
true
);
}
}
return
curl_exec
(
$this
->
connectionID
);
}
/**
* Fixes curl inability to automatically follow location when safe_mode/open_basedir restriction in effect
*
* @return string
* @access protected
*/
protected
function
_followLocationManually
()
{
curl_setopt
(
$this
->
connectionID
,
CURLOPT_HEADER
,
true
);
$data
=
curl_exec
(
$this
->
connectionID
);
$http_code
=
$this
->
getInfo
(
CURLINFO_HTTP_CODE
);
if
(
$http_code
==
301
||
$http_code
==
302
)
{
// safe more or open_basedir restriction - do redirects manually
list
(
$header
)
=
explode
(
"
\r\n\r\n
"
,
$data
,
2
);
preg_match
(
'/(Location:|URI:)(.*?)
\n
/'
,
$header
,
$regs
);
$url
=
trim
(
array_pop
(
$regs
));
$url_parsed
=
parse_url
(
$url
);
if
(
$this
->
lastRedirectCount
==
$this
->
options
[
CURLOPT_MAXREDIRS
]
)
{
return
$this
->
setError
(
CURLE_TOO_MANY_REDIRECTS
,
'Maximum ('
.
$this
->
options
[
CURLOPT_MAXREDIRS
]
.
') redirects followed'
);
}
if
(
isset
(
$url_parsed
)
)
{
curl_setopt
(
$this
->
connectionID
,
CURLOPT_URL
,
$url
);
$this
->
lastRedirectCount
++;
return
$this
->
_followLocationManually
();
}
}
list
(,
$body
)
=
explode
(
"
\r\n\r\n
"
,
$data
,
2
);
return
$body
;
}
/**
* Sets error manually.
*
* @param integer $code Code.
* @param string $message Message.
*
* @return boolean
*/
protected
function
setError
(
$code
,
$message
)
{
$this
->
lastErrorCode
=
$code
;
$this
->
lastErrorMsg
=
$message
;
return
false
;
}
/**
* Returns various info about request made
*
* @param int $info_type
* @return mixed
*
* @see http://www.php.net/manual/ru/function.curl-getinfo.php
* @access public
*/
public
function
getInfo
(
$info_type
)
{
if
(
$info_type
==
CURLINFO_REDIRECT_COUNT
&&
$this
->
followLocationLimited
()
)
{
return
$this
->
lastRedirectCount
;
}
return
curl_getinfo
(
$this
->
connectionID
,
$info_type
);
}
/**
* Returns response headers.
*
* @return array
*/
public
function
getResponseHeaders
()
{
return
$this
->
responseHeaders
;
}
/**
* Detects, that follow location can't be done automatically by curl due safe_mode/open_basedir restrictions
*
* @return bool
* @access protected
*/
protected
function
followLocationLimited
()
{
return
(
defined
(
'SAFE_MODE'
)
&&
SAFE_MODE
)
||
ini_get
(
'open_basedir'
);
}
/**
* Finalizes curl request and saves some data from curl before closing connection
*
* @param bool $close_connection
* @return void
* @access public
*/
public
function
Finalize
(
$close_connection
=
true
)
{
if
(
$this
->
lastErrorCode
==
0
)
{
// error not set manually -> get it from curl
$this
->
lastErrorCode
=
curl_errno
(
$this
->
connectionID
);
$this
->
lastErrorMsg
=
curl_error
(
$this
->
connectionID
);
}
$this
->
lastHTTPCode
=
$this
->
getInfo
(
CURLINFO_HTTP_CODE
);
if
(
$close_connection
)
{
$this
->
CloseConnection
();
}
}
/**
* Closes connection to server
*
* @access public
*/
public
function
CloseConnection
()
{
curl_close
(
$this
->
connectionID
);
if
(
$this
->
debugMode
)
{
$fields_hash
=
Array
(
'ResponseData'
=>
$this
->
lastResponse
,
'ResponseDate'
=>
adodb_mktime
(),
'ResponseHttpCode'
=>
$this
->
lastHTTPCode
,
'CurlError'
=>
$this
->
lastErrorCode
!=
0
?
'#'
.
$this
->
lastErrorCode
.
' ('
.
$this
->
lastErrorMsg
.
')'
:
''
,
);
$this
->
Conn
->
doUpdate
(
$fields_hash
,
TABLE_PREFIX
.
'CurlLog'
,
'LogId = '
.
$this
->
logId
);
}
// restore debug mode setting
$this
->
debugMode
=
kUtil
::
constOn
(
'DBG_CURL'
);
$this
->
_resetSettings
();
}
/**
* Checks, that last curl request was successful
*
* @return bool
* @access public
*/
public
function
isGoodResponseCode
()
{
if
(
$this
->
lastErrorCode
!=
0
)
{
return
false
;
}
return
(
$this
->
lastHTTPCode
==
200
)
||
(
$this
->
lastHTTPCode
>=
300
&&
$this
->
lastHTTPCode
<
310
);
}
}
Event Timeline
Log In to Comment