How to reduce the time CURL takes to send some data? - php

I'm using CURL to send some data to an api , About 300 times using a for loop , It takes some time because the CURL is started and closed each time , I want to reduce the time it takes to loop , But keeps the same functionality.
Here is the code :
//$users = 300.
for ($i=0; $i < count($users); $i++){
// some irrelevant code.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://website.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"src": "'.$numbers_from[$i]['number_from'].'","dst": "'.$users[$i]['international_format'].'", "text": "'.$message.'"}');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Content-Type: application/json",
'Authorization: Basic '. base64_encode("XXXXX:YYYYYY")
));
$message = curl_exec($ch);
curl_close($ch);
// some more code.
}

first some simple optimizations, stop counting $users on each iteration, function calls (eg, count()) are relatively expensive, a variable lookup is much faster. second, use pre-increment instead of post-increment on that $i increment, it's faster & use less cpu (in many compiled languages, the compilers auto-optmize this, but PHP doesn't), but better yet, use ForEach instead of for. it would also be faster to re-use the same curl session over and over instead of creating/deleting it every time. there is an async curl_multi interface, but it's slow and terribly cpu-hungry (no idea why, but it's been like that for years, something weird with PHP's implementation of it), i'd use multiple processes using curl_exec over curl_multi.. try
$code = <<<'CODE'
<?php
// some irrelevant code.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://website.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"src": "'.$argv[1].'","dst": "'.$argv[2].'", "text": "'.$argv[3].'"}');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Content-Type: application/json",
'Authorization: Basic '. base64_encode("XXXXX:YYYYYY")
));
$message = curl_exec($ch);
curl_close($ch);
echo $message;
// some more code.
CODE;
$jobFileh = tmpfile ();
$jobFile = stream_get_meta_data ( $jobFileh ) ['uri'];
file_put_contents($jobFile,$code);
// $users = 300.
$jobs = array ();
for($i = 0, $count = count ( $users ); $i < $count; ++ $i) {
$jobs [] = '/usr/bin/php ' . escapeshellarg ( $jobFile ) . ' ' . escapeshellarg ( $numbers_from [$i] ['number_from'] ) . ' ' . escapeshellarg ( $users [$i] ['international_format'] ) . ' ' . escapeshellarg ( $message );
}
$ret = hhb_exec_multi1 ( $jobs, 100 );
var_dump ( $ret );
die ();
class hhb_exec_multi1_ret {
public $cmd;
public $ret;
public $stdout;
public $stderr;
function __construct(array $attributes) {
foreach ( $attributes as $name => $val ) {
$this->$name = $val;
}
}
}
/**
*
* #param string[] $cmds
* #param int $max_concurrent
* #throws InvalidArgumentException
* #return hhb_exec_multi1_ret[]
*/
function hhb_exec_multi1(array $cmds, int $max_concurrent = 10, $finished_callback = NULL): array {
// TODO: more error checking, if proc_create fail, out of ram, tmpfile() fail, etc
{
// input validation
if ($max_concurrent < 1) {
throw new InvalidArgumentException ( '$max_concurrent must be above 0... and less or equal to' . PHP_INT_MAX );
}
foreach ( $cmds as $tmp ) {
if (! is_string ( $tmp )) {
throw new InvalidArgumentException ( '$cmds must be an array of strings!' );
}
}
}
$ret = array ();
$running = array ();
foreach ( $cmds as $key => $cmd ) {
$current = array (
'cmd' => $cmd,
'ret' => - 1,
'stdout' => tmpfile (),
'stderr' => tmpfile (),
'key' => $key
);
$pipes = [ ];
$descriptorspec = array (
0 => array (
"pipe",
"rb"
),
1 => array (
"file",
stream_get_meta_data ( $current ['stdout'] ) ['uri'],
"wb"
),
2 => array (
"file",
stream_get_meta_data ( $current ['stderr'] ) ['uri'],
"wb"
) // stderr is a file to write to
);
while ( count ( $running ) >= $max_concurrent ) {
// echo ".";
usleep ( 100 * 1000 );
foreach ( $running as $runningkey => $check ) {
$stat = proc_get_status ( $check ['proc'] );
if ($stat ['running']) {
continue;
}
proc_close ( $check ['proc'] );
$check ['ret'] = $stat ['exitcode'];
$stdout = file_get_contents ( stream_get_meta_data ( $check ['stdout'] ) ['uri'] );
fclose ( $check ['stdout'] );
$check ['stdout'] = $stdout;
$stderr = file_get_contents ( stream_get_meta_data ( $check ['stderr'] ) ['uri'] );
fclose ( $check ['stderr'] );
$check ['stderr'] = $stderr;
$checkkey = $check ['key'];
unset ( $check ['key'] );
unset ( $check ['proc'] );
$tmp = ($ret [$checkkey] = new hhb_exec_multi1_ret ( $check ));
unset ( $running [$runningkey] );
if (! empty ( $finished_callback )) {
$finished_callback ( $tmp );
}
}
}
$current ['proc'] = proc_open ( $cmd, $descriptorspec, $pipes );
fclose ( $pipes [0] ); // do it like this because we don't want the children to inherit our stdin, which is the default behaviour if [0] is not defined.
$running [] = $current;
}
while ( count ( $running ) > 0 ) {
// echo ",";
usleep ( 100 * 1000 );
foreach ( $running as $runningkey => $check ) {
$stat = proc_get_status ( $check ['proc'] );
if ($stat ['running']) {
continue;
}
proc_close ( $check ['proc'] );
$check ['ret'] = $stat ['exitcode'];
$stdout = file_get_contents ( stream_get_meta_data ( $check ['stdout'] ) ['uri'] );
fclose ( $check ['stdout'] );
$check ['stdout'] = $stdout;
$stderr = file_get_contents ( stream_get_meta_data ( $check ['stderr'] ) ['uri'] );
fclose ( $check ['stderr'] );
$check ['stderr'] = $stderr;
$checkkey = $check ['key'];
unset ( $check ['key'] );
unset ( $check ['proc'] );
$tmp = ($ret [$checkkey] = new hhb_exec_multi1_ret ( $check ));
unset ( $running [$runningkey] );
if (! empty ( $finished_callback )) {
$finished_callback ( $tmp );
}
}
}
return $ret;
}
now it should do 100 requests simultaneously (configurable with the 2nd parameter to the hhb_exec_multi1 call), which would probably be muuuch faster.

Related

cURL to array_map with utf8_encode in PHP

I'm using a cURL request to grab data from a website and adding them to properties within a loop later. However, I'm stuck on making the data adjustable enough where I can add them directly within the objects.
I have a cURL request that I'm calling that grabbing all the content that I need as below:
public function request()
{
$resource = curl_init();
curl_setopt(
$resource,
CURLOPT_URL,
'lorem ipsum'
);
curl_setopt(
$resource,
CURLOPT_HTTPHEADER,
['API Auth']
);
curl_setopt(
$resource,
CURLOPT_REFERER,
'http://' . $_SERVER['SERVER_NAME'] . '/'
);
curl_setopt(
$resource,
CURLOPT_USERAGENT,
'F'
);
curl_setopt(
$resource,
CURLOPT_RETURNTRANSFER,
1
);
$response = json_decode(curl_exec($resource), true);
if (!curl_errno($resource)) {
$info = curl_getinfo($resource);
echo 'Took ', $info['total_time'], ' seconds to send a request to ', $info['url'], "\n";
};
return $response;
}
When I call the following execution $offices_array = $this->request(); print_r2($offices_array);, this is the return that I receive:
Array
(
[paginator] => Array
(
[total] => 131
[per_page] => 500
[current_page] => 1
[last_page] => 1
[prev_page] =>
[next_page] =>
)
[data] => Array
(
[0] => Array
(
[id] => 1
[name] => Atlanta
)
I'm using this function _csv_to_array:
private function _csv_to_array($filepath) {
$data_array = array();
if(is_readable($filepath)) {
$fp = fopen($filepath, 'r');
while(($data_item = fgetcsv($fp, 1000, "\t")) !== false) {
$data_array[] = array_map('utf8_encode', $data_item);
}
fclose($fp);
}
return $data_array;
}
to print out data as this:
Array
(
[0] => Array
(
[0] => ABU DHABI
[1] => FHI
)
How could I do something similar with the cURL request?

Log In to Google Account through Curl

I am trying to get this script to work:
https://github.com/aaronpk/Google-Voice-PHP-API
Google's recently changed their way to log in to your account. What would be the steps to login through cURL to Google?
It will throw this now when trying to post to the form on this page (https://accounts.google.com/signin/challenge/sl/password):
Type: Exception
Message: Could not parse for GALX or gxf token. Inputs from page: array ()
without checking that code specifically, here's the code i use to login to gmail, using hhb_curl (and note: initially i pretended to be an iPhone, because it was easier to login via the mobile login page than the desktop login page, but eventually i ported it to the desktop version, but there's still some mobile-version-residue in the code. also, sometimes gmail will randomly ask you to verify your recovery email when using this method, thus the $recoveryEmailChallengeAnswer variable. it doesn't happen everytime, but google notice that something is "off" with the login, and thus asks for recovery email verification randomly. my code handles that situation transparently.):
function loginGmail(string $username, string $password, string $recoveryEmailChallengeAnswer, bool $requestHtmlVersion = true): \hhb_curl {
$hc = new hhb_curl ( '', true );
$hc->setopt_array ( array (
CURLOPT_TIMEOUT => 20, // i just have a shitty connection :(
CURLOPT_CONNECTTIMEOUT => 10
) );
if (0) {
$hc->setopt_array ( array (
CURLOPT_USERAGENT => 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1'
) );
}
$html = $hc->exec ( 'https://gmail.com' )->getStdOut ();
$domd = #DOMDocument::loadHTML ( $html );
$inputs = getDOMDocumentFormInputs ( $domd, true, false ) ['gaia_loginform'];
// hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ) & die();
$loginUrl = $domd->getElementById ( "gaia_loginform" )->getAttribute ( "action" );
$inputs ['Email'] = $username;
$html = $hc->setopt_array ( array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query ( $inputs ),
CURLOPT_URL => $loginUrl
) )->exec ()->getStdOut ();
$domd = #DOMDocument::loadHTML ( $html );
$inputs = getDOMDocumentFormInputs ( $domd, true, false ) ['gaia_loginform'];
// hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs );
$loginUrl = $domd->getElementById ( "gaia_loginform" )->getAttribute ( "action" );
$inputs ['Passwd'] = $password;
try {
$starttime = microtime ( true );
$html = $hc->setopt_array ( array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query ( $inputs ),
CURLOPT_URL => $loginUrl
) )->exec ()->getStdOut ();
} finally{
// hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs, (microtime ( true ) - $starttime) ) & die ();
}
$domd = #DOMDocument::loadHTML ( $html );
$xp = new DOMXPath ( $domd );
$loginErrors = $xp->query ( '//span[contains(#class,"error-msg")]' );
$loginErrorText = '';
foreach ( $loginErrors as $tmp ) {
$tmp = trim ( $tmp->textContent );
if (strlen ( $tmp )) {
$loginErrorText .= ' - ' . $tmp;
}
}
$authChallenge = $domd->getElementById ( "challengePickerList" );
if (NULL !== $authChallenge) {
// gotdammit... got an auth challenge page, asking you to choose a challenge
$loginErrorText .= ' - got an auth challenge page, asking you to choose a challenge: ' . trim ( $authChallenge->textContent );
// TODO: automatically select "provide recovery email" here instead of throwing a login error exception.
} else {
if (false !== stripos ( $html, 'Enter recovery email' ) && NULL !== ($authChallenge = $domd->getElementById ( "challenge" ))) {
// got an auth challenge for providing recovery email..
// luckily, we can automatically recover from this.
$inputs = getDOMDocumentFormInputs ( $domd, true, false ) ['challenge'];
assert ( array_key_exists ( 'email', $inputs ) );
$inputs ['email'] = $recoveryEmailChallengeAnswer;
$url = $authChallenge->getAttribute ( "action" );
if (! parse_url ( $url, PHP_URL_HOST )) {
$url = 'https://' . parse_url ( $hc->getinfo ( CURLINFO_EFFECTIVE_URL ), PHP_URL_HOST ) . $url;
}
$html = $hc->setopt_array ( array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query ( $inputs ),
CURLOPT_URL => $url
) )->exec ()->getStdOut ();
$domd = #DOMDocument::loadHTML ( $html );
$xp = new DOMXPath ( $domd );
// TODO: detect incorrect recovery email supplied error here.
}
}
unset ( $authChallenge );
if (! empty ( $loginErrorText )) {
throw new \RuntimeException ( 'errors loggin in: ' . $loginErrorText );
} else {
// logged in! :D
}
if ($requestHtmlVersion) {
// now we need to enable HTML view, it's a <form> POST request, but we can't use getDOMDocumentFormInputs (bug?)
$found = false;
foreach ( $domd->getElementsByTagName ( "form" ) as $form ) {
if (false === stripos ( $form->textContent, "Gmail's basic HTML view, which doesn't require JavaScript" ) && $xp->query ( "./input[#value='Load basic HTML']", $form )->length === 0) {
continue;
}
$found = true;
$url = $form->getAttribute ( "action" );
if (! parse_url ( $url, PHP_URL_HOST )) {
$url = $hc->getinfo ( CURLINFO_EFFECTIVE_URL ) . $url;
}
// hhb_var_dump ( $url ) & die ();
$inputs = [ ];
foreach ( $form->getElementsByTagName ( "input" ) as $input ) {
$name = $input->getAttribute ( "name" );
if (empty ( $name )) {
continue;
}
$inputs [$name] = $input->getAttribute ( "value" );
}
// hhb_var_dump ( $inputs ) & die ();
break;
}
if (! $found) {
$str = 'failed to find HTML version request form!';
// hhb_var_dump ( $str, $hc->getStdErr (), $hc->getStdOut (), $inputs ); // & die ();
throw new \RuntimeException ( $str );
}
$html = $hc->setopt_array ( array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query ( $inputs ),
CURLOPT_URL => $url
) )->exec ()->getStdOut ();
}
hhb_var_dump ( $hc->getStdErr (), $hc->getStdOut (), $inputs ); // & die ();
return $hc;
}
function rightTrim($str, $needle, $caseSensitive = true) {
$strPosFunction = $caseSensitive ? "strpos" : "stripos";
if ($strPosFunction ( $str, $needle, strlen ( $str ) - strlen ( $needle ) ) !== false) {
$str = substr ( $str, 0, - strlen ( $needle ) );
}
return $str;
}
function getDOMDocumentFormInputs(\DOMDocument $domd, bool $getOnlyFirstMatches = false, bool $getElements = true): array {
// :DOMNodeList?
if (! $getOnlyFirstMatches && ! $getElements) {
throw new \InvalidArgumentException ( '!$getElements is currently only implemented for $getOnlyFirstMatches (cus im lazy and nobody has written the code yet)' );
}
$forms = $domd->getElementsByTagName ( 'form' );
$parsedForms = array ();
$isDescendantOf = function (\DOMNode $decendant, \DOMNode $ele): bool {
$parent = $decendant;
while ( NULL !== ($parent = $parent->parentNode) ) {
if ($parent === $ele) {
return true;
}
}
return false;
};
// i can't use array_merge on DOMNodeLists :(
$merged = function () use (&$domd): array {
$ret = array ();
foreach ( $domd->getElementsByTagName ( "input" ) as $input ) {
$ret [] = $input;
}
foreach ( $domd->getElementsByTagName ( "textarea" ) as $textarea ) {
$ret [] = $textarea;
}
foreach ( $domd->getElementsByTagName ( "button" ) as $button ) {
$ret [] = $button;
}
return $ret;
};
$merged = $merged ();
foreach ( $forms as $form ) {
$inputs = function () use (&$domd, &$form, &$isDescendantOf, &$merged): array {
$ret = array ();
foreach ( $merged as $input ) {
// hhb_var_dump ( $input->getAttribute ( "name" ), $input->getAttribute ( "id" ) );
if ($input->hasAttribute ( "disabled" )) {
// ignore disabled elements?
continue;
}
$name = $input->getAttribute ( "name" );
if ($name === '') {
// echo "inputs with no name are ignored when submitted by mainstream browsers (presumably because of specs)... follow suite?", PHP_EOL;
continue;
}
if (! $isDescendantOf ( $input, $form ) && $form->getAttribute ( "id" ) !== '' && $input->getAttribute ( "form" ) !== $form->getAttribute ( "id" )) {
// echo "this input does not belong to this form.", PHP_EOL;
continue;
}
if (! array_key_exists ( $name, $ret )) {
$ret [$name] = array (
$input
);
} else {
$ret [$name] [] = $input;
}
}
return $ret;
};
$inputs = $inputs (); // sorry about that, Eclipse gets unstable on IIFE syntax.
$hasName = true;
$name = $form->getAttribute ( "id" );
if ($name === '') {
$name = $form->getAttribute ( "name" );
if ($name === '') {
$hasName = false;
}
}
if (! $hasName) {
$parsedForms [] = array (
$inputs
);
} else {
if (! array_key_exists ( $name, $parsedForms )) {
$parsedForms [$name] = array (
$inputs
);
} else {
$parsedForms [$name] [] = $tmp;
}
}
}
unset ( $form, $tmp, $hasName, $name, $i, $input );
if ($getOnlyFirstMatches) {
foreach ( $parsedForms as $key => $val ) {
$parsedForms [$key] = $val [0];
}
unset ( $key, $val );
foreach ( $parsedForms as $key1 => $val1 ) {
foreach ( $val1 as $key2 => $val2 ) {
$parsedForms [$key1] [$key2] = $val2 [0];
}
}
}
if ($getElements) {
return $parsedForms;
}
$ret = array ();
foreach ( $parsedForms as $formName => $arr ) {
$ret [$formName] = array ();
foreach ( $arr as $ele ) {
$ret [$formName] [$ele->getAttribute ( "name" )] = $ele->getAttribute ( "value" );
}
}
return $ret;
}

curl_multi_exec is taking forever to give response

my project requires hitting a url against each username stored in an array using curl multi execute.The size of username array is almost 45k and till now i have created another array of 45k urls i want to hit,then to effectively send the requests i have broken that url array into chunks of size 200 each.Then i have passed each chunked array to multi_curl_execute to get the response,but the issue is it takes too much time to receive responses of all 45k requests.I have printed the response array and it was continuously increasing as expected but to print all the responses its taking too much time.Kindly help me as i have to achieve my target by tomorrow.I shall be Much obliged below given is my code
$array1=[1,2,3,4,5,6.....45000];
now creating url with each username as query string
foreach($array1 as $arr)
{
$url[]='abc.com?u='.$arr;
}
//creating chunks
$chunk[]=array_chunk($url,200,true);
//now sending each chunk
for($i=0;$i<sizeof($chunk);$i++)
{
foreach($chunk[$i] as $c_arr)
{
array_push($res,multiRequest($c_arr));
}
}
//my multi_curl function
function multiRequest($data,$options = array())
{
$curly = array();
$result = array();
$mh = curl_multi_init();
$ua = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13';
foreach ($data as $id => $d)
{
$curly[$id]= curl_init();
curl_setopt($curly[$id], CURLOPT_URL,$d);
curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER,true);
curl_setopt($curly[$id], CURLOPT_USERAGENT, $ua);
curl_setopt($curly[$id], CURLOPT_AUTOREFERER, true);
curl_setopt($curly[$id], CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curly[$id], CURLOPT_MAXREDIRS, 20);
curl_setopt($curly[$id], CURLOPT_HTTPGET, true);
curl_setopt($curly[$id], CURLOPT_HEADER,0);
curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER,1);
curl_multi_add_handle($mh, $curly[$id]);
}
$running = null;
do {
curl_multi_exec($mh, $running);
} while($running > 0);
foreach($curly as $id => $c)
{
$result[$id] = curl_multi_getcontent($c);
curl_multi_remove_handle($mh, $c);
}
curl_multi_close($mh);
return $result;
}
Kindly tell me what should i do as it took almost 25-30 minutes to deliver the response of all 45000 requests.And right now i am running this script on my local machine whereas later on it will be scheduled as a cron job on live server
have you tried multiprocessing instead of curl_multi? maybe that's faster? wouldn't be the first time.
try
<?php
$code = <<<'CODE'
<?php
$ch=curl_init();
curl_setopt_array($ch,array(
CURLOPT_URL=>'abc.com?u='.urlencode($argv[1]),
CURLOPT_ENCODING=>"",
CURLOPT_USERAGENT=>'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13',
CURLOPT_AUTOREFERER=>true,
CURLOPT_FOLLOWLOCATION=>true,
CURLOPT_MAXREDIRS=>20
));
curl_exec($ch);
curl_close($ch);
CODE;
$jobFileh = tmpfile ();
$jobFile = stream_get_meta_data ( $jobFileh ) ['uri'];
file_put_contents ( $jobFile, $code );
$jobs = array ();
for($i = 1; $i <= 45000; ++ $i) {
$jobs [] = '/usr/bin/php ' . escapeshellarg ( $jobFile ) . ' ' . escapeshellarg ( ( string ) $i );
}
$starttime = microtime ( true );
$ret = hhb_exec_multi1 ( $jobs, 200 );
$seconds_used = microtime ( true ) - $starttime;
var_dump ( $ret, $seconds_used );
die ();
class hhb_exec_multi1_ret {
public $cmd;
public $ret;
public $stdout;
public $stderr;
function __construct(array $attributes) {
foreach ( $attributes as $name => $val ) {
$this->$name = $val;
}
}
}
/**
*
* #param string[] $cmds
* #param int $max_concurrent
* #throws InvalidArgumentException
* #return hhb_exec_multi1_ret[]
*/
function hhb_exec_multi1(array $cmds, int $max_concurrent = 10, $finished_callback = NULL): array {
// TODO: more error checking, if proc_create fail, out of ram, tmpfile() fail, etc
{
// input validation
if ($max_concurrent < 1) {
throw new InvalidArgumentException ( '$max_concurrent must be above 0... and less or equal to' . PHP_INT_MAX );
}
foreach ( $cmds as $tmp ) {
if (! is_string ( $tmp )) {
throw new InvalidArgumentException ( '$cmds must be an array of strings!' );
}
}
}
$ret = array ();
$running = array ();
foreach ( $cmds as $key => $cmd ) {
$current = array (
'cmd' => $cmd,
'ret' => - 1,
'stdout' => tmpfile (),
'stderr' => tmpfile (),
'key' => $key
);
$pipes = [ ];
$descriptorspec = array (
0 => array (
"pipe",
"rb"
),
1 => array (
"file",
stream_get_meta_data ( $current ['stdout'] ) ['uri'],
"wb"
),
2 => array (
"file",
stream_get_meta_data ( $current ['stderr'] ) ['uri'],
"wb"
) // stderr is a file to write to
);
while ( count ( $running ) >= $max_concurrent ) {
// echo ".";
usleep ( 100 * 1000 );
foreach ( $running as $runningkey => $check ) {
$stat = proc_get_status ( $check ['proc'] );
if ($stat ['running']) {
continue;
}
proc_close ( $check ['proc'] );
$check ['ret'] = $stat ['exitcode'];
$stdout = file_get_contents ( stream_get_meta_data ( $check ['stdout'] ) ['uri'] );
fclose ( $check ['stdout'] );
$check ['stdout'] = $stdout;
$stderr = file_get_contents ( stream_get_meta_data ( $check ['stderr'] ) ['uri'] );
fclose ( $check ['stderr'] );
$check ['stderr'] = $stderr;
$checkkey = $check ['key'];
unset ( $check ['key'] );
unset ( $check ['proc'] );
$tmp = ($ret [$checkkey] = new hhb_exec_multi1_ret ( $check ));
unset ( $running [$runningkey] );
if (! empty ( $finished_callback )) {
$finished_callback ( $tmp );
}
}
}
$current ['proc'] = proc_open ( $cmd, $descriptorspec, $pipes );
fclose ( $pipes [0] ); // do it like this because we don't want the children to inherit our stdin, which is the default behaviour if [0] is not defined.
$running [] = $current;
}
while ( count ( $running ) > 0 ) {
// echo ",";
usleep ( 100 * 1000 );
foreach ( $running as $runningkey => $check ) {
$stat = proc_get_status ( $check ['proc'] );
if ($stat ['running']) {
continue;
}
proc_close ( $check ['proc'] );
$check ['ret'] = $stat ['exitcode'];
$stdout = file_get_contents ( stream_get_meta_data ( $check ['stdout'] ) ['uri'] );
fclose ( $check ['stdout'] );
$check ['stdout'] = $stdout;
$stderr = file_get_contents ( stream_get_meta_data ( $check ['stderr'] ) ['uri'] );
fclose ( $check ['stderr'] );
$check ['stderr'] = $stderr;
$checkkey = $check ['key'];
unset ( $check ['key'] );
unset ( $check ['proc'] );
$tmp = ($ret [$checkkey] = new hhb_exec_multi1_ret ( $check ));
unset ( $running [$runningkey] );
if (! empty ( $finished_callback )) {
$finished_callback ( $tmp );
}
}
}
return $ret;
}
when i ran this code on my laptop to a local nginx server, it executed in 6 minutes and 39 seconds (399 seconds) with the loop set to 45000.
edit: wups, forgot to write the code to the job file (file_put_contents), fixed.

PHP Login using CURL not working

I want to login website bukalapak.com, but I have problem I just got blank page after execute this php, here my code :
var_dump(login_bukalapak());
function login_bukalapak(){
$data_login = array(
'user_session[username]' => 'myusername',
'user_session[password]' => 'mypassword'
);
$url = "https://www.bukalapak.com/user_sessions";
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
$cookie = 'cookies.txt';
$timeout = 30;
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout );
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_POSTFIELDS,$data_login);
$result = curl_exec($ch);
/*$url = "https://www.bukalapak.com/products/new?from=dropdown";
curl_setopt ($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_URL, $url);
$result = curl_exec($ch);*/
curl_close($ch);
return $result;
}
I confuse I just have return blank, how the correct answer to make it run well and return successfully login ?
Thanks.
you're doing many things wrong here.
1: their login system use application/x-www-form-urlencoded encoding for the login POST request body, but your code try to login using multipart/form-data encoding.
2: their login system requires you to have a pre-existing cookie session before logging in, but your code does not obtain a cookie session prior to sending the login request.
3: they use a CSRF token scheme to protect their login, where you need to fetch the csrf token from the page, and add it to your login post fields before sending the login request, called authenticity_token (it's in their html as <input type="hidden" name="authenticity_token" value="<TOKEN>" />), your code makes no attempt to fetch and extract this token prior to logging in.
4: there is a bunch of login parameters you're missing, namely utf8, user_session[remember_me], comeback, button, and as i said previously, authenticity_token - not all of these parameters may be required, or perhaps all of them are, but at least some of them (authenticity_token) is 100% sure to be required, just add them all, unless you wanna waste time figuring out which parameters are required and which is not, it's probably not worth the effort.
5: your code lacks error checking, curl_setopt returns bool(false) if there was a problem setting your settings, and curl_exec returns bool(false) if there was a problem during the transfer
with that in mind, here is a sample implementation in hhb_curl that i think would work with a real username/password:
<?php
require_once ('hhb_.inc.php');
$hc = login_bukalapak ( "foo#bar.com", "password" );
var_dump ( $hc->exec ( 'https://www.bukalapak.com/' )->getStdOut () );
function login_bukalapak(string $username, string $password): \hhb_curl {
$hc = new hhb_curl ( '', true );
$html = $hc->exec ( 'https://www.bukalapak.com/' )->getStdOut ();
$domd = #DOMDocument::loadHTML ( $html );
$data_login = getDOMDocumentFormInputs ( $domd, true, false ) ['new_user_session'];
// var_dump ( $data_login ) & die ();
assert ( isset ( $data_login ['user_session[username]'], $data_login ['user_session[password]'] ), 'username/password field not found in login form!' );
$data_login ['user_session[username]'] = $username;
$data_login ['user_session[password]'] = $password;
$url = "https://www.bukalapak.com/user_sessions";
$html = $hc->setopt_array ( array (
CURLOPT_URL => 'https://www.bukalapak.com/user_sessions',
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query ( $data_login )
) )->exec ()->getStdOut ();
//var_dump ( $html );
$domd = #DOMDocument::loadHTML ( $html );
$xp = new DOMXPath ( $domd );
$loginErrorEles = $xp->query ( '//*[contains(#class,"__error") and not(contains(#class,"hidden"))]' );
$loginErrors = '';
foreach ( $loginErrorEles as $loginError ) {
if (empty ( $loginError->textContent )) {
continue;
}
$loginErrors .= trim ( $loginError->textContent );
}
if (! empty ( $loginErrors )) {
throw new RuntimeException ( 'failed to log in: '.$loginErrors);
}
// assuming logged in successfully
// note that its highly unreliable, they sometimes say "wrong username/password", and someitmes not, seemingly randomly.
return $hc;
}
function getDOMDocumentFormInputs(\DOMDocument $domd, bool $getOnlyFirstMatches = false, bool $getElements = true): array {
// :DOMNodeList?
if (! $getOnlyFirstMatches && ! $getElements) {
throw new \InvalidArgumentException ( '!$getElements is currently only implemented for $getOnlyFirstMatches (cus im lazy and nobody has written the code yet)' );
}
$forms = $domd->getElementsByTagName ( 'form' );
$parsedForms = array ();
$isDescendantOf = function (\DOMNode $decendant, \DOMNode $ele): bool {
$parent = $decendant;
while ( NULL !== ($parent = $parent->parentNode) ) {
if ($parent === $ele) {
return true;
}
}
return false;
};
// i can't use array_merge on DOMNodeLists :(
$merged = function () use (&$domd): array {
$ret = array ();
foreach ( $domd->getElementsByTagName ( "input" ) as $input ) {
$ret [] = $input;
}
foreach ( $domd->getElementsByTagName ( "textarea" ) as $textarea ) {
$ret [] = $textarea;
}
foreach ( $domd->getElementsByTagName ( "button" ) as $button ) {
$ret [] = $button;
}
return $ret;
};
$merged = $merged ();
foreach ( $forms as $form ) {
$inputs = function () use (&$domd, &$form, &$isDescendantOf, &$merged): array {
$ret = array ();
foreach ( $merged as $input ) {
// hhb_var_dump ( $input->getAttribute ( "name" ), $input->getAttribute ( "id" ) );
if ($input->hasAttribute ( "disabled" )) {
// ignore disabled elements?
continue;
}
$name = $input->getAttribute ( "name" );
if ($name === '') {
// echo "inputs with no name are ignored when submitted by mainstream browsers (presumably because of specs)... follow suite?", PHP_EOL;
continue;
}
if (! $isDescendantOf ( $input, $form ) && $form->getAttribute ( "id" ) !== '' && $input->getAttribute ( "form" ) !== $form->getAttribute ( "id" )) {
// echo "this input does not belong to this form.", PHP_EOL;
continue;
}
if (! array_key_exists ( $name, $ret )) {
$ret [$name] = array (
$input
);
} else {
$ret [$name] [] = $input;
}
}
return $ret;
};
$inputs = $inputs (); // sorry about that, Eclipse gets unstable on IIFE syntax.
$hasName = true;
$name = $form->getAttribute ( "id" );
if ($name === '') {
$name = $form->getAttribute ( "name" );
if ($name === '') {
$hasName = false;
}
}
if (! $hasName) {
$parsedForms [] = array (
$inputs
);
} else {
if (! array_key_exists ( $name, $parsedForms )) {
$parsedForms [$name] = array (
$inputs
);
} else {
$parsedForms [$name] [] = $tmp;
}
}
}
unset ( $form, $tmp, $hasName, $name, $i, $input );
if ($getOnlyFirstMatches) {
foreach ( $parsedForms as $key => $val ) {
$parsedForms [$key] = $val [0];
}
unset ( $key, $val );
foreach ( $parsedForms as $key1 => $val1 ) {
foreach ( $val1 as $key2 => $val2 ) {
$parsedForms [$key1] [$key2] = $val2 [0];
}
}
}
if ($getElements) {
return $parsedForms;
}
$ret = array ();
foreach ( $parsedForms as $formName => $arr ) {
$ret [$formName] = array ();
foreach ( $arr as $ele ) {
$ret [$formName] [$ele->getAttribute ( "name" )] = $ele->getAttribute ( "value" );
}
}
return $ret;
}

How can I subtract 3 days from a date?

I have a sync script that syncs domain expiration dates with next due date for billing. Right now the script works great if you want the expiration date to equal the next due date.
But I need the next due date to be three days before the expiration, so I need the code to subtract 3 days from the $expirydate in the following code snippet (Full script code is below):
if ($SyncNextDueDate) {
update_query ( "tbldomains", array ("nextduedate" => $expirydate ), array ("domain" => $domainname ) );
}
Full code:
<?php
require dirname ( __FILE__ ) . '/../../../dbconnect.php';
require ROOTDIR . '/includes/functions.php';
require ROOTDIR . '/includes/registrarfunctions.php';
$cronreport = 'Internet.bs Domain Sync Report<br>
---------------------------------------------------<br>
';
/**
* gets expiration date from domain list command
* #param string $data - command TEXT response
* #return array - associative array having as key the domain name and as value the expiration date
*/
function parseResult($data) {
$result = array ();
$data=strtolower($data);
$arr = explode ( "\n", $data );
$totalDomains = 0;
$assocArr = array ();
foreach ( $arr as $str ) {
list ( $varName, $value ) = explode ( "=", $str );
$varName = trim ( $varName );
$value = trim ( $value );
if ($varName == "domaincount") {
$totalDomains = intval ( $value );
}
$assocArr [$varName] = $value;
}
if ($assocArr ["status"] != "success") {
return false;
}
for($i = 0; $i < $totalDomains; $i ++) {
list ( $y, $m, $d ) = explode ( "/", $assocArr ["domain_" . $i . "_expiration"] );
$status = strtolower ( $assocArr ["domain_" . $i . "_status"] );
if(!is_numeric($y) || !is_numeric($m) || !is_numeric($d)){
$ddat = array ("expiry" => null, "status" => $status );
} else {
$ddat = array ("expiry" => mktime ( 0, 0, 0, $m, $d, $y ), "status" => $status );
}
$result [strtolower ( $assocArr ["domain_" . $i . "_name"] )] = $ddat;
if (isset ( $assocArr ["domain_" . $i . "_punycode"] )) {
$result [strtolower ( $assocArr ["domain_" . $i . "_punycode"] )] = $ddat;
}
}
return $result;
}
$params = getregistrarconfigoptions ( 'internetbs' );
$postfields = array ();
$postfields ['ApiKey'] = $params ['Username'];
$postfields ['Password'] = $params ['Password'];
$postfields ['ResponseFormat'] = 'TEXT';
$postfields ['CompactList'] = 'no';
$testMode = trim(strtolower($params ['TestMode']))==="on";
$SyncNextDueDate = trim(strtolower($params ["SyncNextDueDate"]))==="on";
if ($testMode) {
$url = 'https://testapi.internet.bs/domain/list';
} else {
$url = 'https://api.internet.bs/domain/list';
}
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
curl_setopt ( $ch, CURLOPT_HEADER, 0 );
curl_setopt ( $ch, CURLOPT_USERAGENT, "WHMCS Internet.bs Corp. Expiry Sync Robot" );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt ( $ch, CURLOPT_POST, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $postfields );
$data = curl_exec ( $ch );
$curl_err = false;
if (curl_error ( $ch )) {
$curl_err = 'CURL Error: ' . curl_errno ( $ch ) . ' - ' . curl_error ( $ch );
exit ( 'CURL Error: ' . curl_errno ( $ch ) . ' - ' . curl_error ( $ch ) );
}
curl_close ( $ch );
if ($curl_err) {
$cronreport .= "Error connecting to API: $curl_err";
} else {
$result = parseResult ( $data );
if (! $result) {
$cronreport .= "Error connecting to API:<br>" . nl2br ( $data ) . "<br>";
} else {
$queryresult = select_query ( "tbldomains", "domain", "registrar='internetbs' AND (status='Pending Transfer' OR status='Active')" );
while ( $data = mysql_fetch_array ( $queryresult ) ) {
$domainname = trim ( strtolower ( $data ['domain'] ) );
if (isset ( $result [$domainname] )) {
if(!is_null($result [$domainname] ["expiry"])){
$expirydate = date ( "Y-m-d", $result [$domainname] ["expiry"] );
} else {
$expirydate = false;
}
$status = $result [$domainname] ["status"];
if ($status == 'ok') {
update_query ( "tbldomains", array ("status" => "Active" ), array ("domain" => $domainname ) );
}
if ($expirydate) {
update_query ( "tbldomains", array ("expirydate" => $expirydate ), array ("domain" => $domainname ) );
if ($SyncNextDueDate) {
update_query ( "tbldomains", array ("nextduedate" => $expirydate ), array ("domain" => $domainname ) );
}
$cronreport .= '' . 'Updated ' . $domainname . ' expiry to ' . frommysqldate ( $expirydate ) . '<br>';
}
} else {
$cronreport .= '' . 'ERROR: ' . $domainname . ' - Domain does not appear in the account at Internet.bs.<br>';
}
}
}
}
logactivity ( 'Internet.bs Domain Sync Run' );
sendadminnotification ( 'system', 'WHMCS Internet.bs Domain Syncronisation Report', $cronreport );
?>
$date = new DateTime($expirydate);
$date->sub(new DateInterval('P3D');
$expirydate = $date->format('Y-m-d');
or as a one-liner:
$expirydate = (new DateTime($expirydate))->sub(new DateInterval('P3D'))->format('Y-m-d');
Here's a slightly different method:
$date = new DateTime($expirydate);
$date->modify('-3 days');
$expirydate = $date->format('Y-m-d');

Categories