Generate CSV file on an external FTP server in PHP - php

I have some PHP code that successfully exports a MySQL table to a CSV file.
I would like to add to that code, so instead of saving locally the CSL file is exported to/saved on an external FTP server.
My current code:
//open database connection
require ('../database-config.php');
//name the file
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename=exported-data.csv');
//SQL Query for Data
$sql = "SELECT * FROM data;";
//Prepare Query, Bind Parameters, Excute Query
$STH = $dbh->prepare($sql);
$STH->execute();
//Export to .CSV
$fp = fopen('php://output', 'w');
$first_row = $STH->fetch(PDO::FETCH_ASSOC);
$headers = array_keys($first_row);
fputcsv($fp, $headers); // put the headers
fputcsv($fp, array_values($first_row)); // put the first row
while ($row = $STH->fetch(PDO::FETCH_NUM)) {
fputcsv($fp,$row); // push the rest
}
fclose($fp);
I know I'll need to add some new variables;
$ftp_server="ftp.remotersite.com";
$ftp_path="/path/to/somefile";
$ftp_username="username";
$ftp_userpass="password";
But, I'm not sure the best way to use ftp_put (or should it be ftp_fput?) to transfer to the external destination.
Thanks in advance.

If you have ftp:// URL wrappers enabled, just open the file directly on FTP server:
$fp = fopen('ftp://username:password#ftp.example.com/path/to/somefile', 'w');
If you do not have the wrapers enabled, see:
Creating and uploading a file in PHP to an FTP server without saving locally

Related

Create CSV File in PHP and Save to SFTP using phpseclib

I need to generate a CSV file from a MySQL query and save the file to an SFTP server. I have tried the code below. The CSV file gets created, but it is empty. I also receive an error message in the browser that says Warning: is_file() expects parameter 1 to be a valid path, resource given in regard to this line $sftp->put($fileName, $fp, NET_SFTP_LOCAL_FILE);. If I move fclose($fp); to the last line, I don't get the error but data still doesn't appear in the file. Could someone please let me know how to get the data to save in the file that was created?
$fileName = 'dataFiles/reports/Report Summary/Report Summary.csv';
$sql = mysqli_query($db, "
SELECT *
FROM reports
WHERE reportID = 1
");
$fp = fopen('php://output', 'w');
$first = true;
while($row = mysqli_fetch_assoc($sql)){
if ($first) {
fputcsv($fp, array_keys($row));
$first = false;
}
fputcsv($fp, $row);
}
fclose($fp);
$sftp->put($fileName, $fp, NET_SFTP_LOCAL_FILE);
Try something like this:
<?php
$fp = fopen('php://temp', 'r+');
// do stuff
rewind($fp);
$sftp->put($filename, $fp);
phpseclib (assuming you're using a new enough version) will detect that the second parameter is a stream resource and will try to read from it accordingly.
The second argument is not a handle but the content directly.
I think you could do: stream_get_contents($fp); in the second argument.
$content = stream_get_contents($fp);
fclose($fp);
$sftp->put($fileName, $content, NET_SFTP_LOCAL_FILE);

Unable to append (read and write) text file with php. Using fopen() and fwrite() together

I recently installed Apache, PHP and started working on a small project.
I have the following code.
<?php
$tim=time();
$ip=$_SERVER['REMOTE_ADDR'];
$ipadd=$tim."IPaddress".$ip;
$fp="user_log.txt";// file address
$myfilea = fopen($fp,"a");//open file
fwrite($myfilea,$ipadd.PHP_EOL);//add data to file
echo fread($myfilea,filesize($fp));//read file
fclose($myfilea);//close file
?>
Here is what I can do... I can either use "a" mode to add text or I can use "r" mode to read text. I cant do both. I tried using "a+","r+","ar" etc.
Did I miss something during my setup ???
I am running this on windows 8.1.
Thanks for your help.
You need to rewind the file pointer.
$tim = time();
$ip = $_SERVER['REMOTE_ADDR'];
$ipadd = $tim.'IPaddress'.$ip;
// file address
$fp = 'user_log.txt';
//open file
$myfilea = fopen($fp, 'a+');
//add data to file
fwrite($myfilea, $ipadd.PHP_EOL);
// your file pointer is at the end of the file now
// so rewind before you read
rewind($myfilea);
//read file
echo fread($myfilea, filesize($fp));
//close file
fclose($myfilea);
Try this code, use file_put_contents
file_put_contents = Write a string to a file
$fp="user_log.txt";
$tim=time();
$ip=$_SERVER['REMOTE_ADDR'];
$ipadd=$tim."IPaddress".$ip;
$myfile = file_put_contents($fp, $ipadd.PHP_EOL , FILE_APPEND | LOCK_EX);
And for your code try this, it will check able to open file or not
fopen("logs.txt", "a") or die("Unable to open file!");

fputcsv Creates the file but downloads it empty

I have this piece of PHP code that's intended to retrieve data from a mySQL database, and export it to a CSV file that has to be automatically downloaded after it was created.
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
// fetch mysql table rows
$sql = "select * from users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
$fp = fopen('users.csv', 'w');
while($row = mysqli_fetch_assoc($result)) {
fputcsv($fp, $row);
}
fclose($fp);
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
mysqli_close($connection);
The problem here is that it:
Retrieves the data.
Retrieves the CSV file on the server in the same directory of the export.php file with the data on it.
Downloads the file with the same name BUT it's EMPTY
Thanks.
You're writing it to a file called users.csv, but the file you are forcing the user to download is the output of the page.
As long as your query is correct, once the PHP script has run, there should be a file called users.csv in the same directory as the PHP file that contains the correct data.
You need to output the data to the browser for it to be attributed to the file you're downloading.
Try this:
//Connect to database
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
//Fetch mysql table rows
$sql = "select * from users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
//Close connection
mysqli_close($connection);
//Set $output
$output = "";
//Set header values
$headers = array("Header 1", "Header 2", "Header 3");
//Insert header values to $output
foreach($headers as $h){
$output .= fieldCheck($h) . ",";
}
$output = rtrim($output, ","). "\n";
//Iterate through results
while($row = mysqli_fetch_assoc($result)) {
foreach($row as $cell){
//Comma-separate each value
$output .= fieldCheck($cell).",";
}
//Remove last comma of each line and add newline
$output = rtrim($output, ",") . "\n";
}
//Set headers
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
//Output
echo $output;
exit;
//Function in case of comma in field
function fieldCheck($string){
if(strpos($string, ",") !== false){
$string = '"'.$string.'"';
}
return $string;
}
I have seen this question come up quite a few times and here the user is sending the data to "users.csv" as shown below:
$fp = fopen('users.csv', 'w');
The issue is that unless the file "users.csv" is already created there is nothing to write the data to, so the CSV is blank. The "fopen" does not create the file it only opens an existing file and the "w" directive then instructs "fputcsv" to put it into the file "users.csv" which may not exist and if the file does exist it writes over the existing file.
Here is an explainer PHP script that will send the output (CSV) to a filename of your choice for downloading:
//Connect to database
$connection = mysqli_connect($host, $username, $password, $dbname) or die("Connection Error " . mysqli_error($connection));
//Get the data
//The order and number of elements must match the header below or the data
//will appear in the wrong columns.
$sql = "SELECT FirstName,LastName,Address,City,State,Zip FROM users";
$result = mysqli_query($connection, $sql) or die("Selection Error " . mysqli_error($connection));
//Close connection
mysqli_close($connection);
//Name of the file you want the user to download can be any name but
//use the .CSV file extension so it will be recognized
//as a CSV when downloaded.
$NameOfCSVFileToDownload = "MyCSVFile.csv";
//set headers tells the page what to do
header("Content-Type: application/csv; charset=utf-8");
header("Content-Disposition: attachment;filename=\"$NameOfCSVFileToDownload\"");
//Where to send the data -
//there are several option but sending it to output will insert
//the data into "$NameOfCSVFileToDownload" when complete, your output.
//Output is a way to access I/O streams
$output = fopen("php://output", 'w');
//Add the header or 1st row for your data
//-notice we are sending it to "$output" you can add any names you want
//for this header row but make sure that the number of columns in the header
//matches the number of columns you are retrieving from the database or they
//will not line up when you open up the CSV and things will look scrambled.
fputcsv($output, array('FirstName','LastName','Address','City','State','Zip'));
//Loop through the data and insert the data into "$output"
while($rows = $result->fetch_assoc()){
fputcsv($output, $rows);
}
//Close the "$output" file to complete the write.
fclose($output);
That's all, call the page and it will prompt to open or download the CSV that contains data. If it is still blank make sure your SQL statement is actually pulling data.
You can also review the PHP manual on streams to better understand.
PHP Manual
Combining a few ideas mentioned in the comments:
Output directly to stdout (rather than a users.csv file). This prevents concurrent processes from clashing with the same output file. No need to buffer temporary results in a variable, either.
Use fputcsv()'s 3rd argument to specify ';' as the field separator. No need to rewrite special code for that.
Use array_map() and a custom filter to add quotes around all the fields.
// Helper function to surround a string with double quotes
function pad_with_quotes($s) {
return '"' . $s . '"';
}
// Helper function to output a row to $fp:
function output_row($fp, $row) {
// Separate fields with ';':
fputcsv($fp, array_map('pad_with_quotes', $row), ';');
}
// Send HTTP headers
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="users.csv"');
// Open a pointer to stdout:
$fp = fopen('php://output', 'w'); // TO DO: check for fopen() failure
// Output headers (padded with quotes):
output_row($fp, ['foo', 'bar']); // TO DO: change headers
// DB connection/query goes here; omitted for brevity
// Loop through DB results:
while($row = mysqli_fetch_assoc($result)) {
// Output a row of results:
output_row($fp, row);
}

How to write PrinceXML file to server using PHP

Trying to fwrite the pdf results from PrinceXML to the server (in a new pdf file) instead of exporting via headers to acrobat. The below code displays the results on the browser.
require_once("../library/Prince/prince.php");
$princeSettings = $this->getInvokeArg('bootstrap') >getOption('prince');
$prince = new Prince($princeSettings['path']);
$prince->setHTML(true);
$result = $prince->convert_string_to_passthru($this->htmlView);
$fp = fopen("./files/reports/report.pdf", "w");
fwrite($fp, $result);
fclose($fp);
Figured this out for anyone who want to know...
require_once("../library/Prince/prince.php");
$princeSettings =$this->getInvokeArg('bootstrap')->getOption('prince');
$prince = new Prince($princeSettings['path']); $prince->setHTML(true);
$pdfPath =realpath(APPLICATION_PATH . "/../public/files/reports/report.pdf");
$prince->convert_string_to_file($this->htmlView, $pdfPath);

PHP - Export CSV to FTP rather than download in browser

I have been trying for a few hours now to no avail. I have successfully output my CSV as a download in the browser using:
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=".$csv_filename."");
However I want that output to now go to an FTP server instead, I have got the connection and temp file part sorted but cannot seem to edit the file to output my results.
// create empty variable to be filled with export data
$csv_export = '';
for($i = 0; $i < $field; $i++) {
$csv_export.= mysql_field_name($query,$i).',';
}
// newline (seems to work both on Linux & Windows servers)
$csv_export.= '
';
// loop through database query and fill export variable
while($row = mysql_fetch_array($query)) {
// create line with field values
for($i = 0; $i < $field; $i++) {
$csv_export.= '"'.$row[mysql_field_name($query,$i)].'",';
}
$csv_export.= '
';
}
Above is the part that gets the query data and puts it into the CSV, I have tried incorporating both fputs and fputcsv in the loops to write the rows to the file.
//Upload the temporary file to server
ftp_fput($ftpstream, '/httpdocs/.../abandoned.csv', $temp, FTP_ASCII);
$fp = fopen('var/www/vhosts/.../abandoned.csv', 'w');
fputs($fp, '$csv_export');
fclose($fp);
echo($csv_export);
So, echoing the output works absolutely fine - all I want is that echo'd data written into a CSV file and uploaded to the FTP.
The error I've been given is:
Array ( [type] => 2 [message] => fclose() expects parameter 1 to be resource,
boolean given
So the fp is causing the problem... is it at the open stage or at the writing of csv_export?
Thanks in advance.
Try this
//Write the contents to the temp file
fputs($temp, $csv_export);
//upload the temp file
ftp_fput($ftpstream, '/httpdocs/.../abandoned.csv', $temp, FTP_ASCII);
//close the temp file
fclose($temp);
Your current code is creating an empty file, uploading it, and then creating a separate file. Even if you get it working on a local server, it is an unnecessary step.
Try this, not tested:
$filename = 'abandoned.csv';
$content = $csv_export;
$host = 'yourhost';
$user = 'youruser';
$password = 'yourpass';
//open connection to your ftp server
$stream = stream_context_create(array('ftp' => array('overwrite' => true)));
//authenticate to your ftp server, normal uri syntax
$uri = sprintf('ftp://%s:%s#%s/%s', $user, $password, $host, $filename);
file_put_contents($uri, $content, 0, $stream);
In phpinfo(); you can look for Registered PHP Streams and just use this in most of any cases:
file_put_contents('ftp://user:password#server/your/directory/file.csv', $csvData);
ftp_fput is a right way here.
But you have to prepare FTP connection and authenticate first. Assuming you have $csv_export string in memory:
// connect
$ftp_conn = ftp_connect('ftp.yourserver.net');
// authenticate
$login_result = ftp_login($conn_id, 'ftp_username', 'password');
// prepare output stream
$stream = fopen('data://text/plain,' . $csv_export, 'r');
// try to upload
if (ftp_fput($ftp_conn, '/httpdocs/.../abandoned.csv', $stream, FTP_ASCII)) {
echo "Successfully uploaded\n";
} else {
echo "There was a problem while uploading\n";
}
// close the connection and the file handler
ftp_close($ftp_conn);
fclose($stream);
You're receiving that error because fopen is returning false, which indicates that it was unable to open the file.
If I'm understanding your code, you're uploading abandoned.csv (which presumably exists) to the ftp after opening it in $temp. Is $temp pointing at your local copy of abandon.csv? Because if so, you should close the file stream pointing to it before opening a second one with fopen.
If that's not the issue, then abandoned.csv may not actually exist, in which case you may just be trying to fopen a missing file.

Categories