I'm fairly new to php. I'm using the following script to upload multiple images to a directory. The script works fine. The problem I have is I don't know how to reference the second image so I can store it in a mysql database. The variable $filename stores the image elements of the array.
I want to add the second image to the column itm_pic_name2 in my mysql database. Please can someone point me in the right direction.
public function move($overwrite = false)
{
$field = current($this->_uploaded);
if (is_array($field['name'])) {
foreach ($field['name'] as $number => $filename) {
print_r($field);
//process the multiple upload
$this->_renamed = false;
$this->processFile($filename, $field['error'][$number], $field['size'][$number], $field['type'][$number], $field['tmp_name'][$number], $overwrite);
}
} else {
$this->processFile($field['name'], $field['error'],
$field['size'], $field['type'], $field['tmp_name'], $overwrite);
}
}
protected function processFile($filename, $error, $size, $type, $tmp_name, $overwrite)
{
$OK = $this->checkError($filename, $error);
if ($OK) {
$sizeOK = $this->checkSize($filename, $size);
$typeOK = $this->checkType($filename, $type);
if ($sizeOK && $typeOK) {
$name = $this->checkName($filename, $overwrite);
echo $filename;
echo $type;
echo $size;
$success = move_uploaded_file($tmp_name, $this->_destination . $name);
if ($success) {
//add the amended filename to the array of filenames
$this->_filenames[] = $name;
$this->execSQL("INSERT INTO itm_pic_detail(itm_pic_name, itm_pic_name2,itm_pic_type, itm_pic_size) VALUES (?,?,?)",
array('ssss', $filename, $not_sure_how_to_refence_this_image, $type, $size), true);
$message = "$filename uploaded successfully";
}
if ($this->_renamed) {
$message .= " and renamed $name";
}
$this->_messages[] = $message;
} else {
$this->_messages[] = 'Could not upload ' . $filename;
}
}
}
It's not enough to add a single itm_pic_name2 column to the database. The database structure contains more than just the file name. It contains the size and type as well. Instead, you should be inserting multiple rows in the database - one file per row. Every time you insert a picture, it should return a fileId for the file.
Essentially, what you need is a data table for your form data. That table would have two columns. One for file 1. One for file 2. In that table, you store the unique file id for each file. Then, you use joins to get the file information that you need.
I can't write it out for you exactly, because I don't have any background of what you're trying to do with the files. But, hopefully, you can take this as a start and run with it.
Related
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");
I have made a form on the front end to upload some images. My idea is to automatically rename all files uploaded into unique id's.
I have looked at the SilverStripe API and I do not see anything about that. UploadField API
Is this possible?
Here is my solution bellow, in Silverstripe 3.X we must extend UploadField with another class. Then copy the ''saveTemporaryFile'' function into it.
Just before ''try'', just have to add :
$ext = array_reverse(explode('.',$tmpFile['name'])); // explode filename into array, reverse array, first array key will then be file extension
$tmpFile['name'] = hash_hmac('sha256', $tmpFile['name'], '12345') . '.' . $ext[0];
Results :
class RandomNameUploadField extends UploadField {
protected function saveTemporaryFile($tmpFile, &$error = null) {
// Determine container object
$error = null;
$fileObject = null;
if (empty($tmpFile)) {
$error = _t('UploadField.FIELDNOTSET', 'File information not found');
return null;
}
if($tmpFile['error']) {
$error = $tmpFile['error'];
return null;
}
// Search for relations that can hold the uploaded files, but don't fallback
// to default if there is no automatic relation
if ($relationClass = $this->getRelationAutosetClass(null)) {
// Create new object explicitly. Otherwise rely on Upload::load to choose the class.
$fileObject = Object::create($relationClass);
}
$ext = array_reverse(explode('.',$tmpFile['name'])); // explode filename into array, reverse array, first array key will then be file extension
$tmpFile['name'] = hash_hmac('sha256', $tmpFile['name'], '12345') . '.' . $ext[0];
// Get the uploaded file into a new file object.
try {
$this->upload->loadIntoFile($tmpFile, $fileObject, $this->getFolderName());
} catch (Exception $e) {
// we shouldn't get an error here, but just in case
$error = $e->getMessage();
return null;
}
// Check if upload field has an error
if ($this->upload->isError()) {
$error = implode(' ' . PHP_EOL, $this->upload->getErrors());
return null;
}
// return file
return $this->upload->getFile();
}
}
Thanks #3dgoo to give me a part of the solution!
I don't now about a API but with some code I was able to do that.
You have two possibilities.
First using database.
Second using only code:
$directory = '/teste/www/fotos/';
$files = glob($directory . '*.jpg');
if ( $files !== false )
{
$filecount = count( $files );
$newid = $filecount+1;
$new_name = "foto_".$newid;
$target_file = $directory."/".$new_name;
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
}
else
{
$new_name = "foto_1";
$target_file = $directory."/".$new_name;
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
}
My example is for jpeg but you can look for hall types.
I have simple script like add-to-cart where I can put multiple files for later downloading. When user click on add to cart I store the ID of the file in session and when he click download all based on ID's stored it lookup into database table and download the files.
All the files are stored in same folder and I keep the names in table. The problem that I faced is that in the table I have 3 columns which hold different files(items). This is what I have so far and is working for one column. Question is how to add other two columns?
$files = $_SESSION['itemid'];
$valid_files = array();
if(is_array($files)) {
foreach($files as $file) {
$sql = "SELECT * FROM document_upload WHERE upload_id = :id";
$result = $pdo->prepare($sql);
$result->bindParam(":id", $file);
$result->execute();
$resArray = $result->fetch();
if (file_exists($filePath . $resArray['upload_lesson_plan'])){
$valid_files[] = $resArray;
}
}
}
if(count($valid_files > 0)){
$zip = new ZipArchive();
$zip_name = "zipfile.zip";
if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){
$error .= "* Sorry ZIP creation failed at this time";
}
foreach($valid_files as $res){
$zip->addFile($filePath.$res['upload_lesson_plan']);
// columns that I want to add and take files from...
//$zip->addFile($filePath.$res['upload_worksheet']);
//$zip->addFile($filePath.$res['upload_materials']);
}
Those are both columns which I want to take files from
//$zip->addFile($filePath.$res['upload_worksheet']);
//$zip->addFile($filePath.$res['upload_materials']);
I have tried something like this but doesn't work.. just showing me blank page and doesn't download anything and no errors.
if (file_exists($filePath . $resArray['upload_lesson_plan'] || $filePath . $resArray['upload_worksheet'] || $filePath . $resArray['upload_materials']))
They are stored in columns and they are multiple files in same column comma separated.
Acording to what you said
They are stored in columns and they are multiple files in same column comma separated.
You can try this way. With explode them:
foreach($resArray as $col){
$items = explode(',', $col);
foreach ($items as $item) {
if (file_exists($filePath . trim($item))){
$valid_files[] = $filePath . trim($item);
}
}
And then call them like this
foreach($valid_files as $res){
$zip->addFile($res);
}
just
foreach(['upload_lesson_plan', 'upload_worksheet', 'upload_materials'] as $col){
if (file_exists($filePath . $resArray[$col])){
$valid_files[] = $resArray[$col];
}
}
i have an issue with uploading multiple files to disk. here is my code.
i have a request with 2 pictures that gets sent to a upload function. the 2 pictures are in a var called $multiUpload
$folderPath = '/var/www/';
if (is_array($multiUpload)){
$file = array();
$filename = array();
foreach($multiUpload as $key=>$val){
// get the file extension
$file[] = explode('.',$val);
// create custom file name
$filename[] = time().'.'.$file[$key][1];
//send to the upload function
$this->uploadToDisk($folderPath, $filename[$key]);
// sleep 1 sec so that the pic names will be different
sleep(1);
}
return $filename;
}
public function uploadToDisk($folderPath, $filename)
{
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->setDestination($folderPath);
$adapter->addFilter( 'Rename',array(
'target' => $folderPath."/".$filename,
'overwrite' => true
) );
if ($adapter->receive()) {
$message = "success";
} else {
$message = "fail";
}
return $message;
}
this will return
Array
(
[0] => Array
(
[0] => 1332977938.jpg
[1] => 1332977939.jpg
)
)
but only array[0][0] or 1332977938.jpg will actually get saves to the disk.
Why are they now both get saved? wired
any ideas?
I suspect the second call to uploadToDisk is returning fail because you can only call Zend_File_Transfer_Adapter_Http::receive() once for each file. Since you are not specifying a file when calling receive, it is receiving all of the files the first time you call uploadToDisk and subsequently is failing with a File Upload Attack error.
Here is some code you can try. This tries to receive each file individually and then save them one at a time with each call to uploadToDisk.
A few notes about the code:
The first parameter to uploadToDisk ($val) may need to be changed as I am not sure what the original values are. It should correspond to one of the element names used for the file upload (See Zend_File_Transfer_Adapter_Http::getFileInfo()) for a list of the files.
I changed the method for generating a unique filename so you don't have to sleep(1)
Zend_File_Transfer_Adapter_Abstract::setDestination() is deprecated and will go away in the future. Instead, just use the Rename filter. When using Rename, setDestination() has no effect.
And here it is...
<?php
$folderPath = '/var/www/';
if (is_array($multiUpload)){
$filenames = array();
foreach($multiUpload as $key => $val){
// get the file extension
$ext = explode('.', $val);
$ext = $ext[sizeof($ext) - 1];
// create custom file name
do {
$filename = uniqid(time()) . '.' . $ext;
$diskPath = $folderPath . $filename;
} while (file_exists($diskPath));
$filenames[$key] = $filename;
//send to the upload function
// $val is the file to receive, $diskPath is where it will be moved to
$this->uploadToDisk($val, $diskPath);
}
return $filename;
}
public function uploadToDisk($file, $filename)
{
// create the transfer adapter
// note that setDestination is deprecated, instead use the Rename filter
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->addFilter('Rename', array(
'target' => $filename,
'overwrite' => true
));
// try to receive one file
if ($adapter->receive($file)) {
$message = "success";
} else {
$message = "fail";
}
return $message;
}
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;
}
}