I have PHP page which lists some songs based on a criteria such as album year or something. I just placed a checkbox near to every song. When a visitor selects some check box and press submit button the form sends each value to a php file. In the PHP file the values are stored in an array.
$files_to_zip=array();
for($i=0;$i<count($_POST['song'];i++)
$files_to_zip[]=$_POST['song'][$i];
//'song' is the name of the checkbox in the HTML form
The problem is the PHP file does not create the zip file with the code i wrote.
function create_zip($files = array(),$destination = '',$overwrite = true) {
//if the zip file already exists and overwrite is false, return false
if(file_exists($destination) && !$overwrite) { return false; }
//vars
$valid_files = array();
//if files were passed in...
if(is_array($files)) {
//cycle through each file
foreach($files as $file) {
//make sure the file exists
if(file_exists($file)) {
$valid_files[] = $file;
}
}
}
//if we have good files...
if(count($valid_files)) {
//create the archive
$zip = new ZipArchive();
if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
}
//add the files
foreach($valid_files as $file) {
$zip->addFile($file,$file);
}
//debug
//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
//close the zip -- done!
$zip->close();
//check to make sure the file exists
return file_exists($destination);
}
else
{
return false;
}
}
$files_to_zip = array();
foreach($_POST['song'] as $fileabc)
{
$files_to_zip[]=$fileabc;
}
//if true, good; if false, zip creation failed
$result = create_zip($files_to_zip,'my-archive.zip');
if($result==true)echo "Success"; else echo "failed";
This is the entire code I use in the PHP.
If I set the value for $files_to_zip dynamically such as,
$files_to_zip=array('link1','link2','link3'..)
it works properly.
What is the bug in my code?
Related
I've read similar posts on ZipArchive and GAE but they do not solve my problem. Creating the .zip to the GAE tmp folder exhausts memory as the zip may be 1G or more. Therefore, I'm trying to write directly to a storage bucket.
The output below shows the results of running my zip function. I'm sort of new to GAE/Storage so hoping some more eyes could help me out!
One thing I notice is that $zip->filename = /workspace/gs:/X... Why is "workspace" there and why only one "/" after gs:?
If there is some other method to achieve this, I'm open to suggestions!
I have this working in LAMP, but need to move to GAE. Here's my code of the function that does the zipping:
<?php
function create_zip($files = array(),$fileDestinations = array(),$destination='',$overwrite = false) {
$valid_files = array();
if(is_array($files)) {
//cycle through each file
foreach($files as $file) {
//make sure the file exists OR THE ZIP WON'T BE CREATED
if(file_exists($_SESSION['devStorage'].$file)) {
$valid_files[] = $_SESSION['devStorage'].$file;
}else{
$valid_files[] = $_SERVER['DOCUMENT_ROOT']."/images/default.jpg";
}
}
}
//if we have good files...
if(count($valid_files)) {
if (is_writable(str_replace("https://storage.googleapis.com/","gs://",$_SESSION['devStorage']))) {
echo '<br>'.str_replace("https://storage.googleapis.com/","gs://",$_SESSION['devStorage']).' Folder is writable<br>';
} else {
echo '<br>'.str_replace("https://storage.googleapis.com/","gs://",$_SESSION['devStorage']).' Folder not writable<br>';
}
//create the archive
$zip = new ZipArchive();
if($zip->open($destination, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) {
return "<br>can't open ".$destination;
}
//add the files
foreach($valid_files as $file) {
$zip->addFile($file,current($fileDestinations));
next($fileDestinations);
}
//debug
echo '<br>The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
echo '<br>zip->filename = '.$zip->filename;
//close the zip -- done!
if($zip->close()!==true) {
echo '<br>zip->close error';
}
//check to make sure the file exists
if (!file_exists($destination)) {
return "<br>File does not exist at ".$destination;
}else{
return true;
}
} else {
return "no valid files";
}
}
?>
The resulting output:
gs://X.appspot.com/uploads/ Folder is writable
The zip archive contains 139 files with a status of 0
zip->filename = /workspace/gs:/X.appspot.com/uploads/XSpring2021asof122920_06-03-2021_11-18-45
zip->close error
File does not exist at gs://X.appspot.com/uploads/XSpring2021asof122920_06-03-2021_11-18-45
Thanks for any help offered!
Ended up using ZipStream. My function for zipping is below:
/* creates a compressed zip file */
function create_zip($files = array(),$fileDestinations = array(),$destination='') {
// Autoload the dependencies
require 'vendor/autoload.php';
// enable output of HTTP headers
$options = new ZipStream\Option\Archive();
$options->setSendHttpHeaders(true);
$options->setFlushOutput(true);
$options->setZeroHeader(true);
$options->setStatFiles(true);
// create a new zipstream object
$zip = new ZipStream\ZipStream($destination, $options);
$valid_files = array();
if(is_array($files)) {
//cycle through each file
foreach($files as $file) {
if (($_SERVER["REMOTE_ADDR"]=="127.0.0.1") || ($_SESSION["LAMP"]==1)) {
// //make sure the file exists OR THE ZIP WON'T BE CREATED
//if(file_exists($_SERVER["REQUEST_SCHEME"]."://".$_SERVER['HTTP_HOST'].$file)) {
$valid_files[] = $_SERVER["REQUEST_SCHEME"]."://".$_SERVER['HTTP_HOST'].$file;
//}else{
// $valid_files[] = $_SERVER["REQUEST_SCHEME"]."://".$_SERVER['HTTP_HOST']."/images/default.jpg";
//}
}else{
// //make sure the file exists OR THE ZIP WON'T BE CREATED
//if(file_exists($file)) {
$valid_files[] = $file;
//}else{
// $valid_files[] = $_SERVER["REQUEST_SCHEME"]."://".$_SERVER['HTTP_HOST']."/images/default.jpg";
//}
}
}
}
//if we have good files...
if(count($valid_files)) {
foreach($valid_files as $url) {
// Create Temp File
$fp = tmpfile();
// Download File
$ch = curl_init();
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_URL, $url);
curl_exec($ch);
// Force to write all data
fflush($fp);
// Rewind to the beginning, otherwise the stream is at the end from the start
rewind($fp);
// Add File
$zip->addFileFromStream(current($fileDestinations), $fp);
next($fileDestinations);
// Close the Temp File
curl_close($ch);
fclose($fp);
}
// Finish ZIP
$zip->finish();
return true;
}else{
return "no valid files";
}
}
Is there a function built into PHP that acts like file_exists, but given file contents instead of the file name?
I need this because I have a site where people can upload an image. The image is stored in a file with a name determined by my program (image_0.png image_1.png image_2.png image_3.png image_4.png ...). I do not want my site to have multiple images with the same contents. This could happen if multiple people found a picture on the internet and all of them uploaded it to my site. I would like to check if there is already a file with the contents of the uploaded file to save on storage.
This is how you can compare exactly two files with PHP:
function compareFiles($file_a, $file_b)
{
if (filesize($file_a) == filesize($file_b))
{
$fp_a = fopen($file_a, 'rb');
$fp_b = fopen($file_b, 'rb');
while (($b = fread($fp_a, 4096)) !== false)
{
$b_b = fread($fp_b, 4096);
if ($b !== $b_b)
{
fclose($fp_a);
fclose($fp_b);
return false;
}
}
fclose($fp_a);
fclose($fp_b);
return true;
}
return false;
}
If you keep the sha1 sum of each file you accept you can simply:
if ($known_sha1 == sha1_file($new_file))
You can use a while loop to look look through the contents of all of your files. This is shown in the example below :
function content_exists($file){
$image = file_get_contents($file);
$counter = 0;
while(file_exists('image_' . $counter . '.png')){
$check = file_get_contents('image_' . $counter . '.png');
if($image === $check){
return true;
}
else{
$counter ++;
}
}
return false;
}
The above function looks through all of your files and checks to see if the given image matches an image that is already stored. If the image already exists, true is returned and if the image does not exist false is returned. An example of how you can use this function shown is below :
if(content_exists($_FILES['file']['tmp_name'])){
// upload
}
else{
// do not upload
}
You could store hashed files in a .txt file separated by a \n so that you could use the function below :
function content_exists($file){
$file = hash('sha256', file_get_contents($file));
$files = explode("\n", rtrim(file_get_contents('files.txt')));
if(in_array($file, $files)){
return true;
}
else{
return false;
}
}
You could then use it to determine whether or not you should save the file as shown below :
if(content_exists($_FILES['file']['tmp_name'])){
// upload
}
else{
// do not upload
}
Just make sure that when a file IS stored, you use the following line of code :
file_put_contents('files.txt', hash('sha256', file_get_contents($file)) . "\n");
$dir = "temp/docx";
$errors = array();
$zip = new ZipArchive;
if($zip->open($file_path) === false){
$errors[] = 'Failed to open file';
}
if (empty($errors)) {
$zip->extractTo($dir,"word/document.xml");
$zip->close();
$files = scandir($dir);
print_r($files);
Ok so, basically for some reason the extraction wont work. After seeing the folders empty, I decided to do a scandir to see if they were deleting after the php finished. Nothing. $files variable outputs nothing (ofcourse apart from .. and .).
The zip is actually a docx file, and after explicitly checking for errors, php seems to think the zip_open works, but I'm not sure if this is just a false positive.
I'm wondering if this is due to the fact this is actually a docx file and I need to explicitly save it as a zip file on the server. Or perhaps because this happens straight after being uploaded and the temp file gets deleted before being able to do anything with it (which I imagine is unlikely, as other formats work fine). Perhaps neither of my assumptions are close, or there's the chance I wrote the whole thing wrong. Any help?
Here you go:
<?php
/*Name of the document file*/
$document = 'demo.docx';
/*Directory*/
$dir = "temp/docx/";
/**Function to extract text*/
function extracttext($filename, $action) {
//Check for extension
$ext = end(explode('.', $filename));
//Check if DOCX file
if($ext == 'docx'){
$dataFile = "word/document.xml";
//else it's probebly an ODT file
} else {
$dataFile = "content.xml";
}
//Create a new ZIP archive object
$zip = new ZipArchive;
// Open the archive file
if (true === $zip->open($filename)) {
// If successful, search for the data file in the archive
if (($index = $zip->locateName($dataFile)) !== false) {
// Index found! Now read it to a string
$text = $zip->getFromIndex($index);
// Load XML from a string
// Ignore errors and warnings
$xml = DOMDocument::loadXML($text, LIBXML_NOENT | LIBXML_XINCLUDE | LIBXML_NOERROR | LIBXML_NOWARNING);
if($action == "save"){
// Save xml to file
file_put_contents($dir ."word/document.xml", $xml->saveXML());
return "File succesfully saved.";
} else if($action == "text"){
// Remove XML formatting tags and return the text
return strip_tags($xml->saveXML());
}
}
//Close the archive file
$zip->close();
}
// In case of failure return a message
return "File not found";
}
//Save xml file
echo extracttext($document, "save");
//Echo text from file
echo extracttext($document, "text");
?>
I want to transfer site from shared hosting server to dedicated server.current server has folder,which includes approx. 16000 images...we can not use FTP to download these much images.and i do not have SSH rights? how can i download images from this shared hosting server.
we can not use FTP to download these much images
Nonsense. FTP (the protocol) is perfectly capable of downloading 16000 files. If your FTP program is causing you trouble, simply pick a better FTP program. If you can handle commandline applications, wget is nice, since it supports recursion and continuation.
Unless they are located within a directory that is within the web root of a web application server you are out of luck.
Zip them all, adapted from http://davidwalsh.name/create-zip-php
<?php
function create_zip($files = array(),$destination = '',$overwrite = false) {
//if the zip file already exists and overwrite is false, return false
if(file_exists($destination) && !$overwrite) { return false; }
//vars
$valid_files = array();
//if files were passed in...
if(is_array($files)) {
//cycle through each file
foreach($files as $file) {
//make sure the file exists
if(file_exists($file)) {
$valid_files[] = $file;
}
}
}
//if we have good files...
if(count($valid_files)) {
//create the archive
$zip = new ZipArchive();
if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
return false;
}
//add the files
foreach($valid_files as $file) {
$zip->addFile($file,$file);
}
//debug
//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
//close the zip -- done!
$zip->close();
//check to make sure the file exists
return file_exists($destination);
}
else
{
return false;
}
}
//glob images folder into an array
foreach (glob("*.jpg") as $filename) {
$files_to_zip[]='images/'.$filename;
}
//create the zip
$result = create_zip($files_to_zip,'my-images.zip');
if($result==true){echo'Download Images';
}else{
echo'Could not create zip';}
?>
I have searched the forum but the closest question which is about the control stream did not help or I did not understand so I want to ask a different question.
I have an html form which uploads multiples files to a directory. The upload manager that handles the upload resides in the same script with a different code which I need to pass the file names to for processing.
The problem is that the files get uploaded but they don't get processed by the the other code. I am not sure about the right way to pass the $_FILES['uploadedFile']['tmp_name']) in the adjoining code so the files can be processed with the remaining code. Please find below the script.
More specif explanation:
this script does specifically 2 things. the first part handles file uploads and the second part starting from the italised comment extracts data from the numerous uploaded files. This part has a variable $_infile which is array which is suppose to get the uploaded files. I need to pass the files into this array. so far I struggled and did this: $inFiles = ($_FILES['uploadedFile']['tmp_name']); which is not working. You can see it also in the full code sample below. there is no error but the files are not passed and they are not processed after uploading.
<?php
// This part uploads text files
if (isset($_POST['uploadfiles'])) {
if (isset($_POST['uploadfiles'])) {
$number_of_uploaded_files = 0;
$number_of_moved_files = 0;
$uploaded_files = array();
$upload_directory = dirname(__file__) . '/Uploads/';
for ($i = 0; $i < count($_FILES['uploadedFile']['name']); $i++) {
//$number_of_file_fields++;
if ($_FILES['uploadedFile']['name'][$i] != '') { //check if file field empty or not
$number_of_uploaded_files++;
$uploaded_files[] = $_FILES['uploadedFile']['name'][$i];
//if (is_uploaded_file($_FILES['uploadedFile']['name'])){
if (move_uploaded_file($_FILES['uploadedFile']['tmp_name'][$i], $upload_directory . $_FILES['uploadedFile']['name'][$i])) {
$number_of_moved_files++;
}
}
}
}
echo "Files successfully uploaded . <br/>" ;
echo "Number of files submitted $number_of_uploaded_files . <br/>";
echo "Number of successfully moved files $number_of_moved_files . <br/>";
echo "File Names are <br/>" . implode(',', $uploaded_files);
*/* This is the start of a script to accept the uploaded into another array of it own for* processing.*/
$searchCriteria = array('$GPRMC');
//creating a reference for multiple text files in an array
**$inFiles = ($_FILES['uploadedFile']['tmp_name']);**
$outFile = fopen("outputRMC.txt", "w");
$outFile2 = fopen("outputGGA.txt", "w");
//processing individual files in the array called $inFiles via foreach loop
if (is_array($inFiles)) {
foreach($inFiles as $inFileName) {
$numLines = 1;
//opening the input file
$inFiles = fopen($inFileName,"r");
//This line below initially was used to obtain the the output of each textfile processed.
//dirname($inFileName).basename($inFileName,'.txt').'_out.txt',"w");
//reading the inFile line by line and outputting the line if searchCriteria is met
while(!feof($inFiles)) {
$line = fgets($inFiles);
$lineTokens = explode(',',$line);
if(in_array($lineTokens[0],$searchCriteria)) {
if (fwrite($outFile,$line)===FALSE){
echo "Problem w*riting to file\n";
}
$numLines++;
}
// Defining search criteria for $GPGGA
$lineTokens = explode(',',$line);
$searchCriteria2 = array('$GPGGA');
if(in_array($lineTokens[0],$searchCriteria2)) {
if (fwrite($outFile2,$line)===FALSE){
echo "Problem writing to file\n";
}
}
}
}
echo "<p>For the file ".$inFileName." read ".$numLines;
//close the in files
fclose($_FILES['uploadedFile']['tmp_name']);
fflush($outFile);
fflush($outFile2);
}
fclose($outFile);
fclose($outFile2);
}
?>
Try this upload class instead and see if it helps:
To use it simply Upload::files('/to/this/directory/');
It returns an array of file names that where uploaded. (it may rename the file if it already exists in the upload directory)
class Upload {
public static function file($file, $directory) {
if (!is_dir($directory)) {
if (!#mkdir($directory)) {
throw new Exception('Upload directory does not exists and could not be created');
}
if (!#chmod($directory, 0777)) {
throw new Exception('Could not modify upload directory permissions');
}
}
if ($file['error'] != 0) {
throw new Exception('Error uploading file: '.$file['error']);
}
$file_name = $directory.$file['name'];
$i = 2;
while (file_exists($file_name)) {
$parts = explode('.', $file['name']);
$parts[0] .= '('.$i.')';
$new_file_name = $directory.implode('.', $parts);
if (!file_exists($new_file_name)) {
$file_name = $new_file_name;
}
$i++;
}
if (!#move_uploaded_file($file['tmp_name'], $file_name)) {
throw new Exception('Could not move uploaded file ('.$file['tmp_name'].') to: '.$file_name);
}
if (!#chmod($file_name, 0777)) {
throw new Exception('Could not modify uploaded file ('.$file_name.') permissions');
}
return $file_name;
}
public static function files($directory) {
if (sizeof($_FILES) > 0) {
$uploads = array();
foreach ($_FILES as $file) {
if (!is_uploaded_file($file['tmp_name'])) {
continue;
}
$file_name = static::file($file, $directory);
array_push($uploads, $file_name);
}
return $uploads;
}
return null;
}
}