deprecate z_fetch_url() and friends. Now use Code\Lib\Url::{fetch|get}()

This commit is contained in:
Mike Macgirvin 2022-06-23 00:38:34 -07:00
parent 4c2e191c2d
commit bb9c687de3
33 changed files with 562 additions and 597 deletions

View file

@ -4,6 +4,7 @@ namespace Code\Daemon;
use Code\Web\HTTPSig;
use Code\Lib\Channel;
use Code\Lib\Url;
require_once('include/cli_startup.php');
require_once('include/attach.php');
@ -39,7 +40,7 @@ class Content_importer
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), true, 'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, false, $redirects, [ 'headers' => $headers ]);
$x = Url::get($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, [ 'headers' => $headers ]);
if (! $x['success']) {
logger('no API response', LOGGER_DEBUG);

View file

@ -4,6 +4,7 @@ namespace Code\Daemon;
use Code\Web\HTTPSig;
use Code\Lib\Channel;
use Code\Lib\Url;
require_once('include/cli_startup.php');
require_once('include/attach.php');
@ -37,7 +38,7 @@ class File_importer
];
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), true, 'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id, false, $redirects, [ 'headers' => $headers ]);
$x = Url::get($hz_server . '/api/z/1.0/file/export?f=&zap_compat=1&file_id=' . $attach_id, [ 'headers' => $headers ]);
if (! $x['success']) {
logger('no API response', LOGGER_DEBUG);

View file

@ -9,6 +9,7 @@ use Code\Lib\Connect;
use Code\Lib\Channel;
use Code\Lib\ServiceClass;
use Code\Lib\AccessList;
use Code\Lib\Url;
use Code\Access\PermissionLimits;
use Code\Access\PermissionRoles;
use Code\Access\Permissions;
@ -148,7 +149,7 @@ class Friendica
if ($self_contact['avatar']) {
$p = z_fetch_url($self_contact['avatar'], true);
$p = Url::get($self_contact['avatar'], true);
if ($p['success']) {
$h = explode("\n", $p['header']);
foreach ($h as $l) {

View file

@ -19,6 +19,7 @@ use Code\Lib\Libzot;
use Code\Lib\Nodeinfo;
use Code\Lib\System;
use Code\Lib\Channel;
use Code\Lib\Url;
use Code\Extend\Hook;
use Emoji;
@ -78,7 +79,6 @@ class Activity
public static function fetch($url, $channel = null, $hub = null, $debug = false)
{
$redirects = 0;
if (!$url) {
return null;
}
@ -139,7 +139,7 @@ class Activity
$headers['Authorization'] = 'Bearer ' . $token;
}
$h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), false);
$x = z_fetch_url($url, true, $redirects, ['headers' => $h]);
$x = Url::get($url, ['headers' => $h]);
}
if ($x['success']) {
@ -3289,7 +3289,7 @@ class Activity
$purl = $act->obj['url'];
}
if ($purl) {
$li = z_fetch_url(z_root() . '/linkinfo?binurl=' . bin2hex($purl));
$li = Url::get(z_root() . '/linkinfo?binurl=' . bin2hex($purl));
if ($li['success'] && $li['body']) {
$s['body'] .= "\n" . $li['body'];
} else {

View file

@ -19,6 +19,7 @@ use Code\Access\PermissionLimits;
use Code\Access\Permissions;
use Code\Daemon\Run;
use Code\Lib\System;
use Code\Lib\Url;
use Code\Render\Comanche;
use Code\Lib\ServiceClass;
use Code\Extend\Hook;
@ -1615,7 +1616,7 @@ class Channel
}
$url = $r[0]['hubloc_url'] . '/online/' . substr($webbie, 0, strpos($webbie, '@'));
$x = z_fetch_url($url);
$x = Url::get($url);
if ($x['success']) {
$j = json_decode($x['body'], true);
if ($j) {

View file

@ -4,6 +4,7 @@ namespace Code\Lib;
use Code\Lib\Hashpath;
use Code\Daemon\Run;
use Code\Lib\Url;
class Img_cache
{
@ -59,8 +60,7 @@ class Img_cache
// This is a compromise. We want to cache all the slow sites we can,
// but don't want to rack up too many processes doing so.
$redirects = 0;
$x = z_fetch_url($url, true, $redirects, ['filep' => $fp, 'novalidate' => true, 'timeout' => 120]);
$x = Url::get($url, ['filep' => $fp, 'novalidate' => true, 'timeout' => 120]);
fclose($fp);

View file

@ -17,6 +17,7 @@ use Code\Lib\Activity;
use Code\Lib\Channel;
use Code\Lib\ASCollection;
use Code\Lib\LDSignatures;
use Code\Lib\Url;
use Code\Daemon\Run;
use Code\Extend\Hook;
@ -222,8 +223,7 @@ class Libzot
* @param array $data
* @param array $channel (required if using zot6 delivery)
* @param array $crypto (required if encrypted httpsig, requires hubloc_sitekey and site_crypto elements)
* @return array see z_post_url() for returned data format
* @see z_post_url()
* @return array see Url::post() for returned data format
*
*/
@ -250,9 +250,7 @@ class Libzot
$h = [];
}
$redirects = 0;
return z_post_url($url, $data, $redirects, ((empty($h)) ? [] : ['headers' => $h]));
return Url::post($url, $data, ((empty($h)) ? [] : ['headers' => $h]));
}
public static function nomad($url, $data, $channel = null, $crypto = null) {
@ -272,9 +270,7 @@ class Libzot
$h = [];
}
$redirects = 0;
return z_post_url($url,$data,$redirects,((empty($h)) ? [] : [ 'headers' => $h ]));
return Url::post($url, $data, ((empty($h)) ? [] : ['headers' => $h]));
}
@ -1069,7 +1065,7 @@ class Libzot
* returned to aid communications troubleshooting.
*
* @param string $hub - url of site we just contacted
* @param array $arr - output of z_post_url()
* @param array $arr - output of Url::post()
* @param array $outq - The queue structure attached to this request
*/
@ -2742,7 +2738,7 @@ class Libzot
}
if ($access_policy != ACCESS_PRIVATE) {
$x = z_fetch_url($arr['url'] . '/siteinfo.json');
$x = Url::get($arr['url'] . '/siteinfo.json');
if (!$x['success']) {
$access_policy = ACCESS_PRIVATE;
}

View file

@ -2,6 +2,8 @@
namespace Code\Lib;
use Code\Lib\Url;
class Nodeinfo
{
@ -11,7 +13,7 @@ class Nodeinfo
$m = parse_url($url);
if ($m['scheme'] && $m['host']) {
$s = $m['scheme'] . '://' . $m['host'] . '/.well-known/nodeinfo';
$n = z_fetch_url($s);
$n = Url::get($s);
if ($n['success']) {
$j = json_decode($n['body'], true);
if ($j && $j['links']) {
@ -31,7 +33,7 @@ class Nodeinfo
}
}
if ($href) {
$n = z_fetch_url($href);
$n = Url::get($href);
if ($n['success']) {
return json_decode($n['body'], true);
}

View file

@ -8,7 +8,7 @@ use DOMXPath;
use Code\Lib\Cache;
use Code\Extend\Hook;
use Code\Render\Theme;
use Code\Lib\Url;
class Oembed
{
@ -178,11 +178,8 @@ class Oembed
if ($action !== 'block') {
// try oembed autodiscovery
$redirects = 0;
$result = z_fetch_url(
$result = Url::get(
$furl,
false,
$redirects,
[
'timeout' => 30,
'accept_content' => "text/*",
@ -209,7 +206,7 @@ class Oembed
foreach ($entries as $e) {
$href = $e->getAttributeNode("href")->nodeValue;
$x = z_fetch_url($href . '&maxwidth=' . App::$videowidth);
$x = Url::get($href . '&maxwidth=' . App::$videowidth);
if ($x['success']) {
$txt = $x['body'];
} else {
@ -222,7 +219,7 @@ class Oembed
$entries = $xpath->query("//link[@type='text/json+oembed']");
foreach ($entries as $e) {
$href = $e->getAttributeNode("href")->nodeValue;
$x = z_fetch_url($href . '&maxwidth=' . App::$videowidth);
$x = Url::get($href . '&maxwidth=' . App::$videowidth);
if ($x['success']) {
$txt = $x['body'];
} else {
@ -275,7 +272,7 @@ class Oembed
// as the embed content - which will still need to be purified.
if (preg_match('#\<iframe(.*?)src\=[\'\"](.*?)[\'\"]#', $j['html'], $matches)) {
$x = z_fetch_url($matches[2]);
$x = Url::get($matches[2]);
$orig = $j['html'] = $x['body'];
}

View file

@ -4,11 +4,12 @@
namespace Code\Lib;
use Code\Lib\Libzot;
use Code\Web\HTTPSig;
use Code\Lib\Activity;
use Code\Lib\ActivityStreams;
use Code\Lib\Channel;
use Code\Lib\Libzot;
use Code\Lib\Url;
use Code\Nomad\Receiver;
use Code\Nomad\NomadHandler;
use Code\Extend\Hook;
@ -235,7 +236,7 @@ class Queue
// "post" queue driver - used for diaspora and friendica-over-diaspora communications.
if ($outq['outq_driver'] === 'post') {
$result = z_post_url($outq['outq_posturl'], $outq['outq_msg']);
$result = Url::post($outq['outq_posturl'], $outq['outq_msg']);
if ($result['success'] && $result['return_code'] < 300) {
logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
if ($base) {
@ -349,8 +350,6 @@ class Queue
return;
}
$retries = 0;
$m = parse_url($outq['outq_posturl']);
$headers = [];
@ -368,7 +367,7 @@ class Queue
self::remove($outq['outq_hash']);
}
$result = z_post_url($outq['outq_posturl'], $outq['outq_msg'], $retries, ['headers' => $xhead]);
$result = Url::post($outq['outq_posturl'], $outq['outq_msg'], ['headers' => $xhead]);
if ($result['success'] && $result['return_code'] < 300) {
logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG);
@ -427,7 +426,7 @@ class Queue
// update every queue entry going to this site with the most recent communication error
q(
"update dreport set dreport_log = '%s' where dreport_site = '%s'",
dbesc(z_curl_error($result)),
dbesc(Url::format_error($result)),
dbesc($dr[0]['dreport_site'])
);
}
@ -508,7 +507,7 @@ class Queue
// update every queue entry going to this site with the most recent communication error
q(
"update dreport set dreport_log = '%s' where dreport_site = '%s'",
dbesc(z_curl_error($result)),
dbesc(Url::format_error($result)),
dbesc($dr[0]['dreport_site'])
);

View file

@ -7,7 +7,7 @@ use Code\Lib\Libzotdir;
use Code\Lib\Zotfinger;
use Code\Lib\ASCollection;
use Code\Render\Theme;
use Code\Lib\Url;
class Socgraph {
@ -65,7 +65,7 @@ class Socgraph {
logger('poco_load: ' . $url, LOGGER_DEBUG);
$s = z_fetch_url($url);
$s = Url::get($url);
if (! $s['success']) {
if ($s['return_code'] == 401) {

462
Code/Lib/Url.php Normal file
View file

@ -0,0 +1,462 @@
<?php
namespace Code\Lib;
class Url {
/**
* @brief fetches an URL.
*
* @param string $url
* URL to fetch
* @param bool $binary default false
* TRUE if asked to return binary results (file download)
* @param array $opts (optional parameters) associative array with:
* * \b timeout => int seconds, default system config value or 60 seconds
* * \b headers => array of additional header fields
* * \b http_auth => username:password
* * \b novalidate => do not validate SSL certs, default is to validate using our CA list
* * \b nobody => only return the header
* * \b filep => stream resource to write body to. header and body are not returned when using this option.
* * \b custom => custom request method: e.g. 'PUT', 'DELETE'
* * \b cookiejar => cookie file (write)
* * \b cookiefile => cookie file (read)
* * \b session => boolean; append session cookie *if* $url is our own site
* @param int $redirects default 0
* internal use, recursion counter
*
* @return array an associative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
* * \e boolean \b success => boolean true (if HTTP 2xx result) or false
* * \e string \b header => HTTP headers
* * \e string \b body => fetched content
*/
static public function get($url,$opts = [], $redirects = 0)
{
$ret = array('return_code' => 0, 'success' => false, 'header' => "", 'body' => "");
$passthru = false;
$ch = curl_init($url);
if (($redirects > 8) || (! $ch)) {
return $ret;
}
if (! array_key_exists('request_target', $opts)) {
$opts['request_target'] = 'get ' . get_request_string($url);
}
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_CAINFO, get_capath());
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_ENCODING, '');
$ciphers = @get_config('system', 'curl_ssl_ciphers');
if ($ciphers) {
curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
}
if (x($opts, 'filep')) {
curl_setopt($ch, CURLOPT_FILE, $opts['filep']);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$passthru = true;
}
if (x($opts, 'useragent')) {
curl_setopt($ch, CURLOPT_USERAGENT, $opts['useragent']);
} else {
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; zot)");
}
if (x($opts, 'upload')) {
curl_setopt($ch, CURLOPT_UPLOAD, $opts['upload']);
}
if (x($opts, 'infile')) {
curl_setopt($ch, CURLOPT_INFILE, $opts['infile']);
}
if (x($opts, 'infilesize')) {
curl_setopt($ch, CURLOPT_INFILESIZE, $opts['infilesize']);
}
if (x($opts, 'readfunc')) {
curl_setopt($ch, CURLOPT_READFUNCTION, $opts['readfunc']);
}
// When using the session option and fetching from our own site,
// append the PHPSESSID cookie to any existing headers.
// Don't add to $opts['headers'] so that the cookie does not get
// sent to other sites via redirects
$instance_headers = ((array_key_exists('headers', $opts) && is_array($opts['headers'])) ? $opts['headers'] : []);
if (x($opts, 'session')) {
if (strpos($url, z_root()) === 0) {
$instance_headers[] = 'Cookie: PHPSESSID=' . session_id();
}
}
if ($instance_headers) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $instance_headers);
}
if (x($opts, 'nobody')) {
curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
}
if (x($opts, 'custom')) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $opts['custom']);
}
if (x($opts, 'timeout') && intval($opts['timeout'])) {
curl_setopt($ch, CURLOPT_TIMEOUT, intval($opts['timeout']));
} else {
$curl_time = intval(get_config('system', 'curl_timeout', 60));
curl_setopt($ch, CURLOPT_TIMEOUT, $curl_time);
}
if (x($opts, 'connecttimeout') && intval($opts['connecttimeout'])) {
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, intval($opts['connecttimeout']));
} else {
$curl_contime = intval(@get_config('system', 'curl_connecttimeout', 60));
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $curl_contime);
}
if (x($opts, 'http_auth')) {
// "username" . ':' . "password"
curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
}
if (x($opts, 'cookiejar')) {
curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
}
if (x($opts, 'cookiefile')) {
curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
}
if (x($opts, 'cookie')) {
curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
}
curl_setopt(
$ch,
CURLOPT_SSL_VERIFYPEER,
((x($opts, 'novalidate') && intval($opts['novalidate'])) ? false : true)
);
$prx = @get_config('system', 'proxy');
if (strlen($prx)) {
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_setopt($ch, CURLOPT_PROXY, $prx);
$prxusr = @get_config('system', 'proxyuser');
if (strlen($prxusr)) {
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
}
}
// don't let curl abort the entire application'
// if it throws any errors.
$s = curl_exec($ch);
$base = $s;
$curl_info = curl_getinfo($ch);
$http_code = $curl_info['http_code'];
//logger('fetch_url:' . $http_code . ' data: ' . $s);
$header = '';
// For file redirects, set curl to follow location (indicated by $passthru).
// Then just return success or failure.
if ($passthru) {
if ($http_code >= 200 && $http_code < 300) {
$ret['success'] = true;
}
$ret['return_code'] = $http_code;
curl_close($ch);
return $ret;
}
// Pull out multiple headers, e.g. proxy and continuation headers
// allow for HTTP/2.x without fixing code
while (preg_match('/^HTTP\/[1-3][\.0-9]* [1-5][0-9][0-9]/', $base)) {
$chunk = substr($base, 0, strpos($base, "\r\n\r\n") + 4);
$header .= $chunk;
$base = substr($base, strlen($chunk));
}
if ($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) {
$matches = [];
preg_match('/(Location:|URI:)(.*?)\n/i', $header, $matches);
$newurl = trim(array_pop($matches));
if (strpos($newurl, '/') === 0) {
// We received a redirect to a relative path.
// Find the base component of the original url and re-assemble it with the new location
$base = @parse_url($url);
if ($base) {
unset($base['path']);
unset($base['query']);
unset($base['fragment']);
$newurl = unparse_url($base) . $newurl;
}
}
if ($newurl) {
curl_close($ch);
return self::get($newurl, $opts, ++$redirects);
}
}
$rc = intval($http_code);
$ret['return_code'] = $rc;
$ret['success'] = (($rc >= 200 && $rc <= 299) ? true : false);
if (! $ret['success']) {
$ret['error'] = curl_error($ch);
$ret['debug'] = $curl_info;
logger('error: ' . $url . ': ' . $ret['error'], LOGGER_DEBUG);
logger('debug: ' . self::format_error($ret, true), LOGGER_DATA);
}
$ret['body'] = substr($s, strlen($header));
$ret['header'] = $header;
$ret['request_target'] = $opts['request_target'];
curl_close($ch);
return($ret);
}
/**
* @brief Does a curl post request.
*
* @param string $url
* URL to post
* @param mixed $params
* The full data to post in a HTTP "POST" operation. This parameter can
* either be passed as a urlencoded string like 'para1=val1&para2=val2&...'
* or as an array with the field name as key and field data as value. If value
* is an array, the Content-Type header will be set to multipart/form-data.
* @param array $opts (optional parameters)
* 'timeout' => int seconds, default system config value or 60 seconds
* 'http_auth' => username:password
* 'novalidate' => do not validate SSL certs, default is to validate using our CA list
* 'filep' => stream resource to write body to. header and body are not returned when using this option.
* 'custom' => custom request method: e.g. 'PUT', 'DELETE'
* @param int $redirects = 0
* internal use, recursion counter
*
* @return array an associative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
* * \e boolean \b success => boolean true (if HTTP 2xx result) or false
* * \e string \b header => HTTP headers
* * \e string \b body => content
* * \e string \b debug => from curl_info()
*/
static public function post($url, $params, $opts = [], $redirects = 0)
{
$ret = ['return_code' => 0, 'success' => false, 'header' => '', 'body' => ''];
$ch = curl_init($url);
if (($redirects > 8) || (! $ch)) {
return $ret;
}
if (! array_key_exists('request_target', $opts)) {
$opts['request_target'] = 'post ' . get_request_string($url);
}
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_CAINFO, get_capath());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_ENCODING, '');
$ciphers = get_config('system', 'curl_ssl_ciphers');
if ($ciphers) {
curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
}
if (x($opts, 'filep')) {
curl_setopt($ch, CURLOPT_FILE, $opts['filep']);
curl_setopt($ch, CURLOPT_HEADER, false);
}
if (x($opts, 'useragent')) {
curl_setopt($ch, CURLOPT_USERAGENT, $opts['useragent']);
} else {
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; zot)");
}
$instance_headers = ((array_key_exists('headers', $opts) && is_array($opts['headers'])) ? $opts['headers'] : []);
if (x($opts, 'session')) {
if (strpos($url, z_root()) === 0) {
$instance_headers[] = 'Cookie: PHPSESSID=' . session_id();
}
}
if ($instance_headers) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $instance_headers);
}
if (x($opts, 'nobody')) {
curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
}
if (x($opts, 'custom')) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $opts['custom']);
curl_setopt($ch, CURLOPT_POST, 0);
}
if (x($opts, 'timeout') && intval($opts['timeout'])) {
curl_setopt($ch, CURLOPT_TIMEOUT, intval($opts['timeout']));
} else {
$curl_time = intval(@get_config('system', 'curl_post_timeout', 90));
curl_setopt($ch, CURLOPT_TIMEOUT, $curl_time);
}
if (x($opts, 'connecttimeout') && intval($opts['connecttimeout'])) {
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, intval($opts['connecttimeout']));
} else {
$curl_contime = intval(@get_config('system', 'curl_post_connecttimeout', 90));
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $curl_contime);
}
if (x($opts, 'http_auth')) {
// "username" . ':' . "password"
curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
}
if (x($opts, 'cookiejar')) {
curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
}
if (x($opts, 'cookiefile')) {
curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
}
if (x($opts, 'cookie')) {
curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
}
curl_setopt(
$ch,
CURLOPT_SSL_VERIFYPEER,
((x($opts, 'novalidate') && intval($opts['novalidate'])) ? false : true)
);
$prx = get_config('system', 'proxy');
if (strlen($prx)) {
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_setopt($ch, CURLOPT_PROXY, $prx);
$prxusr = get_config('system', 'proxyuser');
if (strlen($prxusr)) {
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
}
}
// don't let curl abort the entire application
// if it throws any errors.
$s = curl_exec($ch);
$base = $s;
$curl_info = curl_getinfo($ch);
$http_code = $curl_info['http_code'];
$header = '';
// Pull out multiple headers, e.g. proxy and continuation headers
// allow for HTTP/2.x without fixing code
while (preg_match('/^HTTP\/[1-3][\.0-9]* [1-5][0-9][0-9]/', $base)) {
$chunk = substr($base, 0, strpos($base, "\r\n\r\n") + 4);
$header .= $chunk;
$base = substr($base, strlen($chunk));
}
// would somebody take lighttpd and just shoot it?
if ($http_code == 417) {
curl_close($ch);
if ($opts) {
if ($opts['headers']) {
$opts['headers'][] = 'Expect:';
} else {
$opts['headers'] = array('Expect:');
}
} else {
$opts = array('headers' => array('Expect:'));
}
return self::post($url, $params, $opts, ++$redirects);
}
if ($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) {
$matches = [];
preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
$newurl = trim(array_pop($matches));
if (strpos($newurl, '/') === 0) {
// We received a redirect to a relative path.
// Find the base component of the original url and re-assemble it with the new location
$base = @parse_url($url);
if ($base) {
unset($base['path']);
unset($base['query']);
unset($base['fragment']);
$newurl = unparse_url($base) . $newurl;
}
}
if ($newurl) {
curl_close($ch);
if ($http_code == 303) {
return self::get($newurl, $opts, ++$redirects);
} else {
return self::post($newurl, $params, $opts, ++$redirects);
}
}
}
$rc = intval($http_code);
$ret['return_code'] = $rc;
$ret['success'] = (($rc >= 200 && $rc <= 299) ? true : false);
if (! $ret['success']) {
$ret['error'] = curl_error($ch);
$ret['debug'] = $curl_info;
logger('error: ' . $url . ': ' . $ret['error'], LOGGER_DEBUG);
logger('debug: ' . self::format_error($ret,true), LOGGER_DATA);
}
$ret['body'] = substr($s, strlen($header));
$ret['header'] = $header;
$ret['request_target'] = $opts['request_target'];
curl_close($ch);
return($ret);
}
static public function format_error($ret, $verbose = false)
{
$output = EMPTY_STR;
if (isset($ret['debug'])) {
$output .= datetime_convert() . EOL;
$output .= t('url: ') . $ret['debug']['url'] . EOL;
$output .= t('error_code: ') . $ret['debug']['error_code'] . EOL;
$output .= t('error_string: ') . $ret['error'] . EOL;
$output .= t('content-type: ') . $ret['debug']['content_type'] . EOL;
if ($verbose) {
$output .= t('request-header: ') . $ret['debug']['request_header'] . EOL;
}
}
return $output;
}
}

View file

@ -2,6 +2,8 @@
namespace Code\Lib;
use Code\Lib\Url;
/**
* @brief Fetch and return a webfinger for a resource
*
@ -36,8 +38,8 @@ class Webfinger
$url = 'https://' . self::$server . '/.well-known/webfinger?f=&resource=' . self::$resource;
$counter = 0;
$s = z_fetch_url($url, false, $counter, ['headers' => ['Accept: application/jrd+json, */*']]);
$s = Url::get($url, ['headers' => ['Accept: application/jrd+json, */*']]);
if ($s['success']) {
$j = json_decode($s['body'], true);

View file

@ -4,6 +4,7 @@ namespace Code\Lib;
use Code\Web\HTTPSig;
use Code\Lib\Channel;
use Code\Lib\Url;
class ZotURL
{
@ -37,8 +38,6 @@ class ZotURL
$m = parse_url($newurl);
$data = json_encode([ 'zot_token' => random_string() ]);
if ($channel && $m) {
$headers = [
'Accept' => 'application/x-nomad+json, application/x-zot+json',
@ -53,10 +52,7 @@ class ZotURL
$h = [ 'Accept: application/x-nomad+json, application/x-zot+json' ];
}
$result = [];
$redirects = 0;
$x = z_post_url($newurl, $data, $redirects, [ 'headers' => $h ]);
$x = Url::get($newurl, [ 'headers' => $h ]);
if ($x['success']) {
return $x;
}
@ -90,10 +86,8 @@ class ZotURL
// first check sending hub since they have recently communicated with this object
$redirects = 0;
if ($hub) {
$x = z_fetch_url($hub['hubloc_url'] . $path, false, $redirects);
$x = Url::get($hub['hubloc_url'] . $path);
$u = self::parse_response($x);
if ($u) {
return $u;

View file

@ -4,6 +4,7 @@ namespace Code\Lib;
use Code\Web\HTTPSig;
use Code\Lib\Channel;
use Code\Lib\Url;
class Zotfinger
{
@ -41,8 +42,7 @@ class Zotfinger
$result = [];
$redirects = 0;
$x = z_post_url($resource, $data, $redirects, ['headers' => $h]);
$x = Url::post($resource, $data, ['headers' => $h]);
if (in_array(intval($x['return_code']), [ 404, 410 ]) && $recurse) {

View file

@ -5,7 +5,7 @@ namespace Code\Module;
use Code\Lib\Libzotdir;
use Code\Lib\AccessList;
use Code\Web\Controller;
use Code\Lib\Url;
/**
* @brief ACL selector json backend.
@ -327,7 +327,7 @@ class Acloader extends Controller
$query = $url . '?f=';
$query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : '');
$x = z_fetch_url($query);
$x = Url::get($query);
if ($x['success']) {
$t = 0;
$j = json_decode($x['body'], true);

View file

@ -19,7 +19,7 @@ use Code\Extend\Hook;
use Code\Web\HTTPHeaders;
use Sabre\VObject\Reader;
use Code\Render\Theme;
use Code\Lib\Url;
/**
* @file connedit.php
@ -391,8 +391,7 @@ class Connedit extends Controller
if ($cmd === 'fetchvc') {
$url = str_replace('/channel/', '/profile/', $orig_record['xchan_url']) . '/vcard';
$recurse = 0;
$x = z_fetch_url(zid($url), false, $recurse, ['session' => true]);
$x = Url::get(zid($url), ['session' => true]);
if ($x['success']) {
$h = new HTTPHeaders($x['header']);
$fields = $h->fetcharr();

View file

@ -3,6 +3,7 @@
namespace Code\Module\Dev;
use App;
use Code\Lib\Url;
use Code\Lib\ZotURL;
use Code\Lib\Zotfinger;
use Code\Web\Controller;
@ -36,8 +37,7 @@ class Zot_probe extends Controller
$headers = 'Accept: application/x-nomad+json, application/x-zot+json, application/jrd+json, application/json';
$redirects = 0;
$x = z_fetch_url($resource, true, $redirects, ['headers' => [$headers]]);
$x = Url::get($resource, ['headers' => [$headers]]);
}
if ($x['success']) {

View file

@ -14,6 +14,7 @@ use Code\Lib\Socgraph;
use Code\Lib\XConfig;
use Code\Extend\Hook;
use Code\Render\Theme;
use Code\Lib\Url;
require_once('include/bbcode.php');
@ -280,7 +281,7 @@ class Directory extends Controller
// logger('mod_directory: query: ' . $query);
$x = z_fetch_url($query);
$x = Url::get($query);
// logger('directory: return from upstream: ' . print_r($x,true), LOGGER_DATA);
if ($x['success']) {

View file

@ -14,7 +14,7 @@ use Code\Import\Friendica;
use Code\Lib\ServiceClass;
use Code\Extend\Hook;
use Code\Render\Theme;
use Code\Lib\Url;
require_once('include/import.php');
require_once('include/photo_factory.php');
@ -98,10 +98,8 @@ class Import extends Controller
if ($import_posts) {
$api_path .= '&posts=1';
}
$binary = false;
$redirects = 0;
$opts = ['http_auth' => $email . ':' . $password];
$ret = z_fetch_url($api_path, $binary, $redirects, $opts);
$ret = Url::get($api_path, $opts);
if ($ret['success']) {
$data = $ret['body'];
} else {
@ -600,9 +598,7 @@ class Import extends Controller
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), true, 'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, false, $redirects, ['headers' => $headers]);
// logger('z_fetch: ' . print_r($x,true));
$x = Url::get($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, ['headers' => $headers]);
if (!$x['success']) {
logger('no API response');
@ -635,7 +631,7 @@ class Import extends Controller
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), true, 'sha512');
$x = z_fetch_url($hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), false, $redirects, ['headers' => $headers]);
$x = Url::get($hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), ['headers' => $headers]);
if (!$x['success']) {
logger('no API response');

View file

@ -5,7 +5,7 @@ namespace Code\Module;
use App;
use Code\Web\Controller;
use Code\Render\Theme;
use Code\Lib\Url;
require_once('include/import.php');
@ -67,13 +67,11 @@ class Import_items extends Controller
$scheme = 'https://';
$api_path = '/api/red/channel/export/items?f=&zap_compat=1&channel=' . $channelname . '&year=' . intval($year);
$binary = false;
$redirects = 0;
$opts = array('http_auth' => $email . ':' . $password);
$url = $scheme . $servername . $api_path;
$ret = z_fetch_url($url, $binary, $redirects, $opts);
$ret = Url::get($url, $opts);
if (!$ret['success']) {
$ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts);
$ret = Url::get('http://' . $servername . $api_path, $opts);
}
if ($ret['success']) {
$data = $ret['body'];

View file

@ -11,6 +11,7 @@ use Code\Lib\ActivityStreams;
use Code\Lib\Libzot;
use Code\Lib\Channel;
use Code\Lib\Oembed;
use Code\Lib\Url;
use Code\Lib as Zlib;
use Code\Extend\Hook;
@ -121,7 +122,7 @@ class Linkinfo extends Controller
killme();
}
$result = z_fetch_url($url, false, 0, ['novalidate' => true, 'nobody' => true]);
$result = Url::get($url, ['novalidate' => true, 'nobody' => true]);
if ($result['success']) {
$hdrs = [];
$h = explode("\n", $result['header']);
@ -169,7 +170,7 @@ class Linkinfo extends Controller
killme();
}
if (strtolower($type) === 'text/calendar') {
$content = z_fetch_url($url, false, 0, array('novalidate' => true));
$content = Url::get($url, ['novalidate' => true]);
if ($content['success']) {
$ev = ical_to_ev($content['body']);
if ($ev) {
@ -423,7 +424,7 @@ class Linkinfo extends Controller
$siteinfo = [];
$result = z_fetch_url($url, false, 0, array('novalidate' => true));
$result = Url::get($url, ['novalidate' => true]);
if (!$result['success']) {
return $siteinfo;
}

View file

@ -8,6 +8,7 @@ use Code\Web\HTTPSig;
use Code\Lib\Libzot;
use Code\Lib\SConfig;
use Code\Lib\Channel;
use Code\Lib\Url;
use Code\Extend\Hook;
class Magic extends Controller
@ -100,10 +101,6 @@ class Magic extends Controller
$dest = strip_zids($dest);
$dest = strip_query_param($dest, 'f');
// We now post to the OWA endpoint. This improves security by providing a signed digest
$data = json_encode(['OpenWebAuth' => random_string()]);
$headers = [];
$headers['Accept'] = 'application/x-nomad+json, application/x-zot+json';
$headers['Content-Type'] = 'application/x-nomad+json';
@ -113,7 +110,7 @@ class Magic extends Controller
$headers['(request-target)'] = 'post ' . '/owa';
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), true, 'sha512');
$x = z_post_url($owapath, $data, $redirects, ['headers' => $headers]);
$x = Url::get($owapath, ['headers' => $headers]);
logger('owa fetch returned: ' . print_r($x, true), LOGGER_DATA);
if ($x['success']) {
$j = json_decode($x['body'], true);

View file

@ -10,6 +10,7 @@ use Code\Lib\Libzot;
use Code\Lib\Navbar;
use Code\Lib\Libacl;
use Code\Lib\Addon;
use Code\Lib\Url;
use Code\Render\Theme;
@ -212,7 +213,7 @@ class Rpost extends Controller
$channel_acl = $acl->get();
if ($_REQUEST['url']) {
$x = z_fetch_url(z_root() . '/linkinfo?f=&url=' . urlencode($_REQUEST['url']) . '&oembed=1&zotobj=1');
$x = Url::get(z_root() . '/linkinfo?f=&url=' . urlencode($_REQUEST['url']) . '&oembed=1&zotobj=1');
if ($x['success']) {
$_REQUEST['body'] = $_REQUEST['body'] . $x['body'];
}

View file

@ -16,6 +16,7 @@ use PDO;
use Code\Lib\System;
use Code\Web\Controller;
use Code\Lib\Channel;
use Code\Lib\Url;
use Code\Render\Theme;
use Code\Storage\Stdio;
@ -123,7 +124,7 @@ class Setup extends Controller
$siteurl = trim($_POST['siteurl']);
if ($siteurl != z_root()) {
$test = z_fetch_url($siteurl . '/setup/testrewrite');
$test = Url::get($siteurl . '/setup/testrewrite');
if ((!$test['success']) || ($test['body'] !== 'ok')) {
App::$data['url_fail'] = true;
App::$data['url_error'] = $test['error'];
@ -688,15 +689,15 @@ class Setup extends Controller
$url = z_root() . '/setup/testrewrite';
if (function_exists('curl_init')) {
$test = z_fetch_url($url);
$test = Url::get($url);
if (!$test['success']) {
if (strstr($url, 'https://')) {
$test = z_fetch_url($url, false, 0, ['novalidate' => true]);
$test = Url::get($url, ['novalidate' => true]);
if ($test['success']) {
$ssl_error = true;
}
} else {
$test = z_fetch_url(str_replace('http://', 'https://', $url), false, 0, ['novalidate' => true]);
$test = Url::get(str_replace('http://', 'https://', $url), ['novalidate' => true]);
if ($test['success']) {
$ssl_error = true;
}
@ -791,7 +792,7 @@ class Setup extends Controller
// this can set via config. Many distros are now disabling RC4,
// but many existing sites still use it and are unable to change it.
// We do not use SSL for encryption, only to protect session cookies.
// z_fetch_url() is also used to import shared links and other content
// Url::get() is also used to import shared links and other content
// so in theory most any cipher could show up and we should do our best
// to make the content available rather than tell folks that there's a
// weird SSL error which they can't do anything about. This does not affect

View file

@ -3,13 +3,14 @@
namespace Code\Module;
use Code\Web\Controller;
use Code\Lib\Url;
class Sslify extends Controller
{
public function init()
{
$x = z_fetch_url($_REQUEST['url']);
$x = Url::get($_REQUEST['url']);
if ($x['success']) {
$h = explode("\n", $x['header']);
foreach ($h as $l) {

View file

@ -2,7 +2,9 @@
namespace Code\Storage;
// The Hubzilla CalDAV client will store calendar information in the 'cal' DB table.
use Code\Lib\Url;
// The CalDAV client will store calendar information in the 'cal' DB table.
// Event information will remain in the 'event' table. In order to implement CalDAV on top of our
// existing system, there is an event table column called vdata. This will hold the "one true record"
// of the event in VCALENDAR format. When we receive a foreign event, we will pick out the fields
@ -102,12 +104,8 @@ class CalDAVClient
$auth = $this->username . ':' . $this->password;
$recurse = 0;
$x = z_fetch_url(
$x = Url::get(
$this->url,
true,
$recurse,
['headers' => $headers,
'http_auth' => $auth,
'custom' => 'PROPFIND',
@ -143,10 +141,8 @@ class CalDAVClient
$auth = $this->username . ':' . $this->password;
$recurse = 0;
$x = z_fetch_url(
$x = Url::get(
$this->url,
true,
$recurse,
['headers' => $headers,
'http_auth' => $auth,
'custom' => 'REPORT',

View file

@ -16,6 +16,7 @@ use Code\Lib\Navbar;
use Code\Lib\Stringsjs;
use Code\Extend\Hook;
use Code\Lib\Head;
use Code\Lib\Url;
/**
* @file boot.php
@ -2457,10 +2458,10 @@ function z_get_temp_dir() {
*/
function z_check_cert() {
if(strpos(z_root(), 'https://') !== false) {
$x = z_fetch_url(z_root() . '/siteinfo.json');
$x = Url::get(z_root() . '/siteinfo');
if(! $x['success']) {
$recurse = 0;
$y = z_fetch_url(z_root() . '/siteinfo.json', false, $recurse, ['novalidate' => true]);
$y = Url::get(z_root() . '/siteinfo', ['novalidate' => true]);
if($y['success'])
cert_bad_email();
}

View file

@ -9,7 +9,7 @@ use Code\Lib\Libsync;
use Code\Lib\Channel;
use Code\Extend\Hook;
use Code\Render\Theme;
use Code\Lib\Url;
function abook_store_lowlevel($arr)
{
@ -590,7 +590,7 @@ function random_profile()
return EMPTY_STR; // Couldn't get a random channel
}
if ($checkrandom) {
$x = z_fetch_url($r[0]['xchan_url']);
$x = Url::get($r[0]['xchan_url']);
if ($x['success']) {
return $r[0]['xchan_hash'];
} else {

View file

@ -8,6 +8,7 @@ use Code\Lib\Connect;
use Code\Lib\LibBlock;
use Code\Lib\Channel;
use Code\Lib\ServiceClass;
use Code\Lib\Url;
use Code\Daemon\Run;
use Code\Access\PermissionRoles;
use Code\Access\PermissionLimits;
@ -1675,8 +1676,6 @@ function sync_files($channel, $files)
continue;
}
$redirects = 0;
$m = parse_url($fetch_url);
$headers = [
@ -1688,7 +1687,7 @@ function sync_files($channel, $files)
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), true, 'sha512');
$x = z_post_url($fetch_url . '/' . $att['hash'], $parr, $redirects, [ 'filep' => $fp, 'headers' => $headers]);
$x = Url::post($fetch_url . '/' . $att['hash'], $parr, [ 'filep' => $fp, 'headers' => $headers]);
fclose($fp);
@ -1771,7 +1770,6 @@ function sync_files($channel, $files)
logger('failed to open storage file.', LOGGER_NORMAL, LOG_ERR);
continue;
}
$redirects = 0;
$m = parse_url($fetch_url);
@ -1784,7 +1782,7 @@ function sync_files($channel, $files)
$headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], Channel::url($channel), true, 'sha512');
$x = z_post_url($fetch_url . '/' . $att['hash'], $parr, $redirects, [ 'filep' => $fp, 'headers' => $headers]);
$x = Url::post($fetch_url . '/' . $att['hash'], $parr, [ 'filep' => $fp, 'headers' => $headers]);
fclose($fp);

View file

@ -12,6 +12,7 @@ use Code\Lib\System;
use Code\Lib\Keyutils;
use Code\Lib\LDSignatures;
use Code\Lib\Addon;
use Code\Lib\Url;
use Code\Web\HTTPSig;
use Code\Daemon\Run;
use Code\Extend\Hook;
@ -32,484 +33,6 @@ function get_capath()
return appdirpath() . '/library/cacert.pem';
}
/**
* @brief fetches an URL.
*
* @param string $url
* URL to fetch
* @param bool $binary default false
* TRUE if asked to return binary results (file download)
* @param int $redirects default 0
* internal use, recursion counter
* @param array $opts (optional parameters) associative array with:
* * \b timeout => int seconds, default system config value or 60 seconds
* * \b headers => array of additional header fields
* * \b http_auth => username:password
* * \b novalidate => do not validate SSL certs, default is to validate using our CA list
* * \b nobody => only return the header
* * \b filep => stream resource to write body to. header and body are not returned when using this option.
* * \b custom => custom request method: e.g. 'PUT', 'DELETE'
* * \b cookiejar => cookie file (write)
* * \b cookiefile => cookie file (read)
* * \b session => boolean; append session cookie *if* $url is our own site
*
* @return array an associative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
* * \e boolean \b success => boolean true (if HTTP 2xx result) or false
* * \e string \b header => HTTP headers
* * \e string \b body => fetched content
*/
function z_fetch_url($url, $binary = false, $redirects = 0, $opts = [])
{
$ret = array('return_code' => 0, 'success' => false, 'header' => "", 'body' => "");
$passthru = false;
$ch = @curl_init($url);
if (($redirects > 8) || (! $ch)) {
return $ret;
}
if (! array_key_exists('request_target', $opts)) {
$opts['request_target'] = 'get ' . get_request_string($url);
}
@curl_setopt($ch, CURLOPT_HEADER, true);
@curl_setopt($ch, CURLINFO_HEADER_OUT, true);
@curl_setopt($ch, CURLOPT_CAINFO, get_capath());
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
@curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@curl_setopt($ch, CURLOPT_ENCODING, '');
$ciphers = @get_config('system', 'curl_ssl_ciphers');
if ($ciphers) {
@curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
}
if (x($opts, 'filep')) {
@curl_setopt($ch, CURLOPT_FILE, $opts['filep']);
@curl_setopt($ch, CURLOPT_HEADER, false);
@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$passthru = true;
}
if (x($opts, 'useragent')) {
@curl_setopt($ch, CURLOPT_USERAGENT, $opts['useragent']);
} else {
@curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; zot)");
}
if (x($opts, 'upload')) {
@curl_setopt($ch, CURLOPT_UPLOAD, $opts['upload']);
}
if (x($opts, 'infile')) {
@curl_setopt($ch, CURLOPT_INFILE, $opts['infile']);
}
if (x($opts, 'infilesize')) {
@curl_setopt($ch, CURLOPT_INFILESIZE, $opts['infilesize']);
}
if (x($opts, 'readfunc')) {
@curl_setopt($ch, CURLOPT_READFUNCTION, $opts['readfunc']);
}
// When using the session option and fetching from our own site,
// append the PHPSESSID cookie to any existing headers.
// Don't add to $opts['headers'] so that the cookie does not get
// sent to other sites via redirects
$instance_headers = ((array_key_exists('headers', $opts) && is_array($opts['headers'])) ? $opts['headers'] : []);
if (x($opts, 'session')) {
if (strpos($url, z_root()) === 0) {
$instance_headers[] = 'Cookie: PHPSESSID=' . session_id();
}
}
if ($instance_headers) {
@curl_setopt($ch, CURLOPT_HTTPHEADER, $instance_headers);
}
if (x($opts, 'nobody')) {
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
}
if (x($opts, 'custom')) {
@curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $opts['custom']);
}
if (x($opts, 'timeout') && intval($opts['timeout'])) {
@curl_setopt($ch, CURLOPT_TIMEOUT, intval($opts['timeout']));
} else {
$curl_time = intval(get_config('system', 'curl_timeout', 60));
@curl_setopt($ch, CURLOPT_TIMEOUT, $curl_time);
}
if (x($opts, 'connecttimeout') && intval($opts['connecttimeout'])) {
@curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, intval($opts['connecttimeout']));
} else {
$curl_contime = intval(@get_config('system', 'curl_connecttimeout', 60));
@curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $curl_contime);
}
if (x($opts, 'http_auth')) {
// "username" . ':' . "password"
@curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
}
if (x($opts, 'cookiejar')) {
@curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
}
if (x($opts, 'cookiefile')) {
@curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
}
if (x($opts, 'cookie')) {
@curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
}
@curl_setopt(
$ch,
CURLOPT_SSL_VERIFYPEER,
((x($opts, 'novalidate') && intval($opts['novalidate'])) ? false : true)
);
$prx = @get_config('system', 'proxy');
if (strlen($prx)) {
@curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
@curl_setopt($ch, CURLOPT_PROXY, $prx);
$prxusr = @get_config('system', 'proxyuser');
if (strlen($prxusr)) {
@curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
}
}
if ($binary) {
@curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
}
// don't let curl abort the entire application'
// if it throws any errors.
$s = @curl_exec($ch);
$base = $s;
$curl_info = @curl_getinfo($ch);
$http_code = $curl_info['http_code'];
//logger('fetch_url:' . $http_code . ' data: ' . $s);
$header = '';
// For file redirects, set curl to follow location (indicated by $passthru).
// Then just return success or failure.
if ($passthru) {
if ($http_code >= 200 && $http_code < 300) {
$ret['success'] = true;
}
$ret['return_code'] = $http_code;
@curl_close($ch);
return $ret;
}
// Pull out multiple headers, e.g. proxy and continuation headers
// allow for HTTP/2.x without fixing code
while (preg_match('/^HTTP\/[1-3][\.0-9]* [1-5][0-9][0-9]/', $base)) {
$chunk = substr($base, 0, strpos($base, "\r\n\r\n") + 4);
$header .= $chunk;
$base = substr($base, strlen($chunk));
}
if ($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) {
$matches = [];
preg_match('/(Location:|URI:)(.*?)\n/i', $header, $matches);
$newurl = trim(array_pop($matches));
if (strpos($newurl, '/') === 0) {
// We received a redirect to a relative path.
// Find the base component of the original url and re-assemble it with the new location
$base = @parse_url($url);
if ($base) {
unset($base['path']);
unset($base['query']);
unset($base['fragment']);
$newurl = unparse_url($base) . $newurl;
}
}
if ($newurl) {
@curl_close($ch);
return z_fetch_url($newurl, $binary, ++$redirects, $opts);
}
}
$rc = intval($http_code);
$ret['return_code'] = $rc;
$ret['success'] = (($rc >= 200 && $rc <= 299) ? true : false);
if (! $ret['success']) {
$ret['error'] = curl_error($ch);
$ret['debug'] = $curl_info;
$dbg = [
'url' => $ret['debug']['url'],
'content_type' => $ret['debug']['content_type'],
'error_code' => ((isset($ret['debug']['error_code'])) ? $ret['debug']['error_code'] : 0),
'request_header' => $ret['debug']['request_header']
];
logger('z_fetch_url: error: ' . $url . ': ' . $ret['error'], LOGGER_DEBUG);
logger('z_fetch_url: debug: ' . print_r($dbg, true), LOGGER_DATA);
}
$ret['body'] = substr($s, strlen($header));
$ret['header'] = $header;
$ret['request_target'] = $opts['request_target'];
if (x($opts, 'debug')) {
$ret['debug'] = $curl_info;
}
@curl_close($ch);
return($ret);
}
/**
* @brief Does a curl post request.
*
* @param string $url
* URL to post
* @param mixed $params
* The full data to post in a HTTP "POST" operation. This parameter can
* either be passed as a urlencoded string like 'para1=val1&para2=val2&...'
* or as an array with the field name as key and field data as value. If value
* is an array, the Content-Type header will be set to multipart/form-data.
* @param int $redirects = 0
* internal use, recursion counter
* @param array $opts (optional parameters)
* 'timeout' => int seconds, default system config value or 60 seconds
* 'http_auth' => username:password
* 'novalidate' => do not validate SSL certs, default is to validate using our CA list
* 'filep' => stream resource to write body to. header and body are not returned when using this option.
* 'custom' => custom request method: e.g. 'PUT', 'DELETE'
*
* @return array an associative array with:
* * \e int \b return_code => HTTP return code or 0 if timeout or failure
* * \e boolean \b success => boolean true (if HTTP 2xx result) or false
* * \e string \b header => HTTP headers
* * \e string \b body => content
* * \e string \b debug => from curl_info()
*/
function z_post_url($url, $params, $redirects = 0, $opts = [])
{
// logger('url: ' . $url);
// logger('params: ' . print_r($params,true));
// logger('opts: ' . print_r($opts,true));
$ret = array('return_code' => 0, 'success' => false, 'header' => "", 'body' => "");
$ch = curl_init($url);
if (($redirects > 8) || (! $ch)) {
return $ret;
}
if (! array_key_exists('request_target', $opts)) {
$opts['request_target'] = 'post ' . get_request_string($url);
}
@curl_setopt($ch, CURLOPT_HEADER, true);
@curl_setopt($ch, CURLINFO_HEADER_OUT, true);
@curl_setopt($ch, CURLOPT_CAINFO, get_capath());
@curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@curl_setopt($ch, CURLOPT_POST, 1);
@curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
@curl_setopt($ch, CURLOPT_ENCODING, '');
$ciphers = @get_config('system', 'curl_ssl_ciphers');
if ($ciphers) {
@curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, $ciphers);
}
if (x($opts, 'filep')) {
@curl_setopt($ch, CURLOPT_FILE, $opts['filep']);
@curl_setopt($ch, CURLOPT_HEADER, false);
}
if (x($opts, 'useragent')) {
@curl_setopt($ch, CURLOPT_USERAGENT, $opts['useragent']);
} else {
@curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; zot)");
}
$instance_headers = ((array_key_exists('headers', $opts) && is_array($opts['headers'])) ? $opts['headers'] : []);
if (x($opts, 'session')) {
if (strpos($url, z_root()) === 0) {
$instance_headers[] = 'Cookie: PHPSESSID=' . session_id();
}
}
if ($instance_headers) {
@curl_setopt($ch, CURLOPT_HTTPHEADER, $instance_headers);
}
if (x($opts, 'nobody')) {
@curl_setopt($ch, CURLOPT_NOBODY, $opts['nobody']);
}
if (x($opts, 'custom')) {
@curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $opts['custom']);
@curl_setopt($ch, CURLOPT_POST, 0);
}
if (x($opts, 'timeout') && intval($opts['timeout'])) {
@curl_setopt($ch, CURLOPT_TIMEOUT, intval($opts['timeout']));
} else {
$curl_time = intval(@get_config('system', 'curl_post_timeout', 90));
@curl_setopt($ch, CURLOPT_TIMEOUT, $curl_time);
}
if (x($opts, 'connecttimeout') && intval($opts['connecttimeout'])) {
@curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, intval($opts['connecttimeout']));
} else {
$curl_contime = intval(@get_config('system', 'curl_post_connecttimeout', 90));
@curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $curl_contime);
}
if (x($opts, 'http_auth')) {
// "username" . ':' . "password"
@curl_setopt($ch, CURLOPT_USERPWD, $opts['http_auth']);
}
if (x($opts, 'cookiejar')) {
@curl_setopt($ch, CURLOPT_COOKIEJAR, $opts['cookiejar']);
}
if (x($opts, 'cookiefile')) {
@curl_setopt($ch, CURLOPT_COOKIEFILE, $opts['cookiefile']);
}
if (x($opts, 'cookie')) {
@curl_setopt($ch, CURLOPT_COOKIE, $opts['cookie']);
}
@curl_setopt(
$ch,
CURLOPT_SSL_VERIFYPEER,
((x($opts, 'novalidate') && intval($opts['novalidate'])) ? false : true)
);
$prx = get_config('system', 'proxy');
if (strlen($prx)) {
@curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
@curl_setopt($ch, CURLOPT_PROXY, $prx);
$prxusr = get_config('system', 'proxyuser');
if (strlen($prxusr)) {
@curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
}
}
// don't let curl abort the entire application
// if it throws any errors.
$s = @curl_exec($ch);
$base = $s;
$curl_info = @curl_getinfo($ch);
$http_code = $curl_info['http_code'];
$header = '';
// Pull out multiple headers, e.g. proxy and continuation headers
// allow for HTTP/2.x without fixing code
while (preg_match('/^HTTP\/[1-3][\.0-9]* [1-5][0-9][0-9]/', $base)) {
$chunk = substr($base, 0, strpos($base, "\r\n\r\n") + 4);
$header .= $chunk;
$base = substr($base, strlen($chunk));
}
// would somebody take lighttpd and just shoot it?
if ($http_code == 417) {
curl_close($ch);
if ($opts) {
if ($opts['headers']) {
$opts['headers'][] = 'Expect:';
} else {
$opts['headers'] = array('Expect:');
}
} else {
$opts = array('headers' => array('Expect:'));
}
return z_post_url($url, $params, ++$redirects, $opts);
}
if ($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) {
$matches = [];
preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
$newurl = trim(array_pop($matches));
if (strpos($newurl, '/') === 0) {
// We received a redirect to a relative path.
// Find the base component of the original url and re-assemble it with the new location
$base = @parse_url($url);
if ($base) {
unset($base['path']);
unset($base['query']);
unset($base['fragment']);
$newurl = unparse_url($base) . $newurl;
}
}
if ($newurl) {
curl_close($ch);
if ($http_code == 303) {
return z_fetch_url($newurl, false, ++$redirects, $opts);
} else {
return z_post_url($newurl, $params, ++$redirects, $opts);
}
}
}
$rc = intval($http_code);
$ret['return_code'] = $rc;
$ret['success'] = (($rc >= 200 && $rc <= 299) ? true : false);
if (! $ret['success']) {
$ret['error'] = curl_error($ch);
$ret['debug'] = $curl_info;
$dbg = [
'url' => $ret['debug']['url'],
'content_type' => $ret['debug']['content_type'],
'error_code' => $ret['debug']['error_code'],
'request_header' => $ret['debug']['request_header']
];
logger('z_post_url: error: ' . $url . ': ' . $ret['error'], LOGGER_DEBUG);
logger('z_post_url: debug: ' . print_r($dbg, true), LOGGER_DATA);
}
$ret['body'] = substr($s, strlen($header));
$ret['header'] = $header;
$ret['request_target'] = $opts['request_target'];
if (x($opts, 'debug')) {
$ret['debug'] = $curl_info;
}
curl_close($ch);
return($ret);
}
function z_curl_error($ret)
{
$output = EMPTY_STR;
if (isset($ret['debug'])) {
$output .= datetime_convert() . EOL;
$output .= t('url: ') . $ret['debug']['url'] . EOL;
$output .= t('error_code: ') . $ret['debug']['error_code'] . EOL;
$output .= t('error_string: ') . $ret['error'] . EOL;
$output .= t('content-type: ') . $ret['debug']['content_type'] . EOL;
}
return $output;
}
function json_return_and_die($x, $content_type = 'application/json', $debug = false)
{
@ -1276,11 +799,8 @@ function webfinger_rfc7033($webbie)
}
logger('fetching url from resource: ' . $rhs . ':' . $webbie);
$counter = 0;
$s = z_fetch_url(
'https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource . (($zot) ? '&zot=1' : ''),
false,
$counter,
$s = Url::get(
'https://' . $rhs . '/.well-known/webfinger?f=&resource=' . $resource,
[ 'headers' => [ 'Accept: application/jrd+json, application/json, */*' ] ]
);
@ -1728,7 +1248,7 @@ function get_repository_version($branch = 'release')
$path = "https://raw.codeberg.page/streams/" . PLATFORM_NAME . "/@$branch/version.php";
$x = z_fetch_url($path);
$x = Url::get($path);
if ($x['success']) {
$y = preg_match('/define(.*?)STD_VERSION(.*?)([0-9.].*)\'/', $x['body'], $matches);
if ($y) {
@ -1853,7 +1373,7 @@ function probe_api_path($host)
foreach ($schemes as $scheme) {
foreach ($paths as $path) {
$curpath = $scheme . '://' . $host . $path;
$x = z_fetch_url($curpath);
$x = Url::get($curpath);
if ($x['success'] && ! strpos($x['body'], 'not implemented')) {
return str_replace('version', '', $curpath);
}

View file

@ -7,6 +7,7 @@ use Code\Lib\Config;
use Code\Lib\Img_cache;
use Code\Lib\Hashpath;
use Code\Lib\Channel;
use Code\Lib\Url;
/**
* @brief Return a PhotoDriver object.
@ -241,7 +242,7 @@ function import_remote_xchan_photo($src, $xchan, $thing = false)
$thumb = z_root() . '/xp/' . $hash . '-5' . (($thing) ? '.obj' : EMPTY_STR);
$micro = z_root() . '/xp/' . $hash . '-6' . (($thing) ? '.obj' : EMPTY_STR);
$result = z_fetch_url($src, true);
$result = Url::get($src);
if ($result['success']) {
$type = guess_image_type($src, $result['header']);
@ -348,8 +349,7 @@ function import_remote_cover_photo($src, $xchan)
logger('failed to create storage file.', LOGGER_NORMAL);
return false;
}
$redirects = 0;
$result = z_fetch_url($src, true, $redirects, ['filep' => $fp]);
$result = Url::get($src, ['filep' => $fp]);
fclose($fp);
if ($result['success']) {
@ -385,7 +385,7 @@ function import_channel_photo_from_url($photo, $aid, $uid)
$type = null;
if ($photo) {
$result = z_fetch_url($photo, true);
$result = Url::get($photo);
if ($result['success']) {
$img_str = $result['body'];

View file

@ -12,6 +12,7 @@ use Code\Access\PermissionLimits;
use Code\Web\HTTPHeaders;
use Code\Daemon\Run;
use Code\Lib\ServiceClass;
use Code\Lib\Url;
use Code\Extend\Hook;
use Code\Render\Theme;
@ -1077,9 +1078,7 @@ function profile_photo_set_profile_perms($uid, $profileid = 0)
function fetch_image_from_url($url, &$mimetype)
{
$redirects = 0;
$x = z_fetch_url($url, true, $redirects, [ 'novalidate' => true ]);
$x = Url::get($url, [ 'novalidate' => true ]);
if ($x['success']) {
$ht = new HTTPHeaders($x['header']);
$hdrs = $ht->fetcharr();