PHP Curl Error code 25 - php

I tried to search the web but I couldn't find a clear point on the issue I'm trying to figure out.
I have a situation where the uploaded files will be sent over to another server via FTP (Egnyte). I have a localhost setup and it succeeded uploading the files to FTP but not in the live site where it gives me a curl error (25) - in FTP, STOR command has been denied. It has a further error message of "Failed FTP upload: 451". What bugs me even more is, the server has staging / dev cloned from the live site and it perfectly works there.
What could be in the localhost setup that I should look in the server of the live site and/or possible causes of the curl error? Curl is enabled in the live server btw.
My curl options (considering variables are supplied properly and ftp has been connected):
// connection options
$options = array(
CURLOPT_USERPWD => $username . ':' . $password,
CURLOPT_SSL_VERIFYPEER => false, // don't verify SSL
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_FTP_SSL => CURLFTPSSL_ALL, // require SSL For both control and data connections
CURLOPT_FTPSSLAUTH => CURLFTPAUTH_DEFAULT, // let cURL choose the FTP authentication method (either SSL or TLS)
CURLOPT_UPLOAD => true,
CURLOPT_PORT => $port,
CURLOPT_TIMEOUT => 30,
);
and here's my upload function:
public function upload( $file_name, $file ) {
// set file name
if ( ! curl_setopt( $this->curl_handle, CURLOPT_URL, $this->url . $file_name ))
throw new Exception ( "Could not set cURL file name: $file_name" );
/* Open the file for writing */
$file_stream = fopen($file, "r");
/* Open a memory for writing */
$stream = fopen('php://temp' , "wb");
/* Read the file and write it to the stream 1kb at a time */
while ($data = fread($file_stream, 1024))
fwrite($stream, $data);
// rewind the stream pointer
rewind( $stream );
// set the file to be uploaded
if ( ! curl_setopt( $this->curl_handle, CURLOPT_INFILE, $stream ) )
throw new Exception( "Could not load file $file_name" );
// upload file
if ( ! curl_exec( $this->curl_handle ) ) {
throw new Exception( sprintf( 'Could not upload file. cURL Error: [%s] - %s', curl_errno( $this->curl_handle ), curl_error( $this->curl_handle ) ) );
}
// close the stream handle
fclose( $stream );
fclose( $file_stream );
}

I actually figured this issue 2 weeks ago.
It seems like in the live site, it fails when there are spaces in the filename. For now, replacing the spaces with underscores should be good. Not yet sure though why its perfectly fine to have spaces when I integrated the script in the localhost setup.

Related

Getting a file from a dynamic download URL with PHP in wordpress

I'm trying to automate downloading a file (in this case it's a PDF invoice) on wordpress order completed hook.
I have first tried to download it using wp_remote_get which seemed simple, but without success (no file downloads):
function download_pdf_invoice__on_order_completed( $order_id, $order ) {
wp_remote_get( "http://www.africau.edu/images/default/sample.pdf" );
}
add_action( 'woocommerce_order_status_completed', 'download_pdf_invoice__on_order_completed', 20, 2 );
So far I have managed to make it work and download any file with cURL as long as the extension is in the URL, but I can't get it to work with my dynamic download URL, which is this test/demo URL:
https://www.moloni.com/downloads/index.php?action=getDownload&h=b75b2d99c08c56480da0c5dff4900b4a&d=189279574&e=teste#moloni.com&i=1&t=n
function action_woocommerce_admin_order_get_invoice_pdf($url){
//The resource that we want to download.
$fileUrl = 'https://www.moloni.com/downloads/index.php?action=getDownload&h=b75b2d99c08c56480da0c5dff4900b4a&d=189279574&e=teste#moloni.com&i=1&t=n';
//The path & filename to save to.
$saveTo = '/myserver/public_html/wp-content/plugins/my-custom-functionality-master/logo.jpg';
//Open file handler.
$fp = fopen($saveTo, 'w+');
//If $fp is FALSE, something went wrong.
if($fp === false){
throw new Exception('Could not open: ' . $saveTo);
}
//Create a cURL handle.
$ch = curl_init($fileUrl);
//Pass our file handle to cURL.
curl_setopt($ch, CURLOPT_FILE, $fp);
//Timeout if the file doesn't download after 20 seconds.
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
//Execute the request.
curl_exec($ch);
//Get the HTTP status code.
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//Close the cURL handler.
curl_close($ch);
}
add_action( 'woocommerce_order_status_completed', 'action_woocommerce_admin_order_get_invoice_pdf', 20, 2 );
However if I replace the $fileUrl with this sample PDF http://www.africau.edu/images/default/sample.pdf then it will work
I have considered implementing some sort of error / log to be able to see what errors could be caused by the code however I have not figured it out how to do this under these circumstances of hooking the download to the woocommerce order completed action
Use file_get_contents to download file from URL.
$fileUrl = 'https://www.moloni.com';
$saveTo = ABSPATH . '/wp-content/plugins/my-custom-functionality-master/logo.jpg'
file_put_contents(
$saveTo,
file_get_contents($fileUrl)
);

PHP: read a remote file (ideally using fopen)

I'd like to read a remote text file (ideally using fopen) using PHP. My script works using fopen when I'm using this function on a local file.
I've tried:
$file = fopen ("http://abc.abc.abc", "r");
if (!$file) {
echo "<p>Unable to open remote file.\n";
exit;
}
and I got:
Warning: fopen(http://abc.abc.abc): failed to open stream: No connection could be made because the target machine actively refused it. in C:\xampp\htdocs\NMR\nmrTest5.php on line 2 Unable to open remote file.
I've read that phpseclib could be a good option and since I can access to my files using WinSCP (SFTP) or by using Puttyfor I tried this (after copying all the files from phpseclib to my directory) hoping that I could copy locally the file and then read it with fopen (not the best thing for met but I could live with that):
include('Net/SFTP.php');
$sftp = new Net_SFTP('abc.abc.abc');
if (!$sftp->login('username', 'pass')) {
exit('Login Failed');
}
and I got:
Notice: No compatible server to client encryption algorithms found in C:\xampp\htdocs\NMR\Net\SSH2.php on line 1561
Login Failed
Interstingly, I got a different message if I was connected to the server (using WinSCP):
Notice: Error reading from socket in C:\xampp\htdocs\NMR\Net\SSH2.php on line 3362
Notice: Connection closed by server in C:\xampp\htdocs\NMR\Net\SSH2.php on line 1471
Login Failed
Any idea on how I could get it to work? Ideally I would use fopen but I'm open to other solution.
I've just been working through this exact problem myself and couldn't find any good documentation in any one single place for how to accomplish this.
I have just made a logging service that uses Monolog and basically makes a custom stream handler based on the log files that are being written to/created. As such it requires a resource (such as one created by fopen) in order to write the log files to an SFTP server.
I had it working using the ssh2 library like this:
$connection = ssh2_connect($this->host, 22);
ssh2_auth_password($connection, $this->user, $this->password);
$sftp = ssh2_sftp($connection);
//some stuff to do with whether the file already exists or not
$fh=fopen("ssh2.sftp://$sftp".ssh2_sftp_realpath($sftp,".")."/$this->logName/$this->fileName", 'a+');
return new StreamHandler($fh);
Everything was working beautifully until I went to integrate the service into a different project and realised this was only working on my development machine because it has the libssh2 library installed as outlined in this question.
Unfortunately, the production server is not so easy to add libraries to. I therefore found myself looking for a different solution.
I have used phpseclib in other projects but only for basic get(), put() and some nlist() calls.
In order to get this working I had to use a Stream object. Not very well documented but there is a good discussion here.
Based on the info there, plus some digging around in the SFTP class, particularly the get() function, this is how I managed to achieve the same functionality using phpseclib
SFTP\Stream::register();
$sftpFileSystem = new SFTP($this->host);
if (!$sftpFileSystem->login($this->user, $this->password)) {
throw new Exception("Error logging in to central logging system. Please check the local logs and email for details", 1);
}
$context = [
'sftp' => [
'sftp' => $sftpFileSystem
],
];
//some stuff to do with whether the file already exists or not
$remote_file = $sftpFileSystem->realpath('test.txt');
$sftpStream = fopen("sftp://.{$remote_file}", 'a+', null, stream_context_create($context));
if (!$sftpStream) {
exit(1);
}
return new StreamHandler($sftpStream);
note the dot (.) after the sftp:// in the call to fopen(). It wasted me a good half an hour!
This is how I ended fixing my problem usng phpseclib as suggested by #neubert in the comments of my question.
I first added the phpseclib folder on my server. Then I used this code in my PHP file to get access to my file on a remote server:
//needed for phpseclib
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
include_once('Net/SFTP.php');
//connection to the server
$sftp = new Net_SFTP('abc.abc.abc');
if (!$sftp->login('my_login', 'my_password')) {
exit('Login Failed');
}
//dump entire file in a string, convert to an array and check number of lines
else {
$text = $sftp->get('full_path_to_my_file');
}
$myArray = explode("\n", $text);
$nbline = count($myArray);
I have faced similiar issues with fopen.
Curl is useful for these purposes.
Please check with the following basic example function(if the url is https, please uncomment the CURLOPT_SSL_VERIFYPEER = FALSE line).
$url = '***THE URL***';
$result = get_web_page_by_curl($url);
if ($result['errno'] != 0) echo 'error: bad url, timeout, redirect loop ...';
if ($result['http_code'] != 200) echo 'error: no page, no permissions, no service ...';
else {
$page = $result['content'];
echo $page;
}
function get_web_page_by_curl($url) {
$agent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)";
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_USERAGENT => $agent, // who am i
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
//CURLOPT_SSL_VERIFYPEER => FALSE // this line makes it work under https
);
$ch = curl_init($url);
curl_setopt_array($ch, $options);
$content = curl_exec($ch);
$err = curl_errno($ch);
$errmsg = curl_error($ch);
$header = curl_getinfo($ch);
curl_close($ch);
$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}

curl windows: the provided file handle is not writable

I have a random "hang without errors" while executing curl requests. I'm trying to detect the origin as the web server and php logs don't show any errors, so I tried to enable CURLOT_STDERR.
I have the following code:
$file = 'curl.txt';
$curl = curl_init();
$curl_log = fopen($file, 'rw');
var_export(is_writable($file));
$url = 'http://www.google.com';
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_VERBOSE => 1,
CURLOPT_STDERR => $curl_log,
CURLOPT_RETURNTRANSFER => 1
));
$response = curl_exec($curl);
rewind($curl_log);
$output= fread($curl_log, 2048);
echo '<pre>'. print_r($output, 1). '</pre>';
fclose($curl_log);
is_writable returns true, but curl execution dies with the following error:
curl_setopt_array(): the provided file handle is not writable
I'm running PHP 7.0.15 Fast CGI on a Windows Machine.
It seems the CURL user doesn't have write permissions, but I can write on that file using other PHP functions.
Thank you very much for your help hanshenrik.
var_dump(fwrite($curl_log,'test')); returned 0.
So I changed the line $curl_log = fopen($file, 'rw'); to $curl_log = fopen($file, 'a'); and problem solved.

fedora commons ingest object via REST error

I recently set up FEDORA for a project I am working on to catalogue various
media. I want to be able to consume files (datastreams) via the FEDORA REST api. I managed to create a digital object via curl with no issues at all. I also managed to add an html page as a datastream to the digital object mentioned above with no problems as well.
However, adding a digital object with other content types/file types fails and throws an internal server error 500. On checking the logs, the following error appears:
[http-bio-8080-exec-18] (DatastreamResource) Error with uploaded://47 : XML was not well-formed. Invalid byte 1 of 1-byte UTF-8 sequence
The following is my code snippet of how I am ingesting the files:
$url = "http://localhost:8080/fedora/objects/changeme:5/datastreams/NEWDS8?controlGroup=X&dsLabel=LAZLO";
$file = "namibia2015.pdf";
// Build cURL options
$userPassword = "fedoraAdmin:test123"; // username:password
$verifyPeer = false; // false for ignoring self signed certificates
$headers = array("Accept: text/xml", "Content-Type: " . mime_content_type($file));
$fileContents = file_get_contents($file);
$curlOptions = array(
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_USERPWD => $userPassword,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_SSL_VERIFYPEER => $verifyPeer,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $fileContents
);
$curlHandle = curl_init();
$success = curl_setopt_array($curlHandle, $curlOptions);
throw new Exception(
sprintf(
"curl_setopt_array(...) failed. Error: %s. Info: %s",
curl_error($curlHandle),
print_r(curl_getinfo($curlHandle), true)
),
curl_errno($curlHandle)
);
}
$curlReturn = curl_exec($curlHandle);
$httpCode = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE);
I came across this post How can I ingest an image into Fedora Commons using PHP? tried the suggested method but still no luck.
What am I doing wrong? What am I missing? Why is it possible to add an html file datastream to the digital object but it fails when I try to
add .jpeg, .pdf, .txt etc?
I finally fixed the error. The exception was being caused by the way I was structuring my URL parameters in my curl request. Using a URL with the following format:
$url = "http://localhost:8080/fedora/objects/changeme:5/datastreams/NEWDS8?controlGroup=X&dsLabel=LAZLO";
will throw the error. Instead, you have to build an http query of all the options you want attached to the POST request. I did that as follows:
$array = array();
$array['dsID'] = '5' ;
$array['controlGroup'] = 'M' ;
$array['altIDS'] = 'Other';
$array['versionable'] = true;
$array['dsLabel'] = 'The pic';
$array['logMessage'] = 'Example log message';
$link = "http://localhost:8080/fedora/objects/changeme:5/datastreams/newobject";
$params = http_build_query($array);
$url = $link.'?'.$params; //add the http query parameters to the url
Thereafter, I made my curl request as before and it will successfully create a data stream attached to the digital object.
Hope this will help someone in the future.

Copy file from remote server using PHP over HTTP

I want to copy a file using PHP over http from a link in this format
http://myserver.com/?id=1234
if I open the link, the download of the file starts ...
So I assume that server redirects to a .mp3 file to start the download.
So how to copy/download the file from the remote server to to my server (localhost)?
Just to gove an example of what Victor is tlking about with cURL:
$options = array(
CURLOPT_FILE => '/local/path/for/file.mp3',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_URL => 'http://myserver.com/?id=1234',
);
$ch = curl_init();
curl_setopt_array($ch, $options);
curl_exec($ch);
I'm assuming here that the remote server sends the complete file over HTTP. You could use a library such as curl to send an HTTP request and store the received data as a file (using CURLOPT_FILE).
If your local PHP server is correctly configured, you can also use copy to copy from a remote URL to a local path.
$handle = fopen("http://www.example.com/", "rb");
$contents = '';
while (!feof($handle)) {
$contents .= fread($handle, 8192);
}
fclose($handle);
from
http://php.net/manual/en/function.fread.php
Try using a notification callback (read here for mor informations http://www.php.net/manual/function.stream-notification-callback.php)
e.g. you could to this if you like to copy:
function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max)
{
if($notification_code == STREAM_NOTIFY_PROGRESS)
{
// save $bytes_transferred and $bytes_max to file or database
}
}
$ctx = stream_context_create();
stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
copy($remote_url,$Local_target,$ctx);
Another PHP file could read the saved $bytes_transferred and $bytes_max and show a nice progress bar.

Categories