I have an error displaying images in php, my script used to work, and now it doesnt :(.
My Script is this:
$image_id = intval($_REQUEST['id']);
//Query database for our images data and grab it fromt the array returned
$result = mysql_query(sprintf("SELECT data, file_size, mime_type FROM _system_image WHERE id = %d;", $image_id));
$row = mysql_fetch_array($result);
//Set the headers so the browser knows an image is coming and then echo out the data
header("Content-type: " . $row['mime_type']);
header("Content-length: " . $row['file_size']);
echo $row['data'];
exit();
And my script for uploading photos is:
//Create an array of potential errors for uploading images
$image_uploading_errors = array(1 => 'Maximum file size in php.ini exceeded',
2 => 'Maximum file size in HTML form exceeded',
3 => 'Only part of the file was uploaded',
4 => 'No file was selected to upload.');
//Get the filename and size (validation of size is done in html part!)
$filename = $_FILES[SINGLE_IMAGE_UPLOAD_NAME]['name'];
$img_size = $_FILES[SINGLE_IMAGE_UPLOAD_NAME]['size'];
//Use the tmp name, to 'getimagesize' which returns an array of info (not just images size!) and also to get the data from the image
$info = getimagesize($_FILES[SINGLE_IMAGE_UPLOAD_NAME]['tmp_name']);
$data = file_get_contents($_FILES[SINGLE_IMAGE_UPLOAD_NAME]['tmp_name']);
//Get the mime type from the img_size (an array of info)
$mime_type = $info['mime'];
//Put all the info into a new image object
//(img_id, album_id, album_pos, name, low_res_mime, low_res_size, high_res_mime, high_res_size, available_sizes, date_uploaded, date taken, caption)
$img = new Image(NULL, NULL, NULL, $filename, NULL, NULL, $mime_type, $file_size, NULL, new DateTime(), NULL, NULL);
$img->set_high_res_data($data);
//Return the image!
return $img;
The Image class used is something that I've written myself, and all the variables like $mime_type do go correctly into the database.
I feel like this may be a repeat question, but I have looked on here, and none of the solutions (that I found) were useful!
EDIT:
The error is "The image '...' cannot be displayed because it contains errors." Where '...' is the file name.
I usually try to display the image with the html: wher %d is an integer.
The problem is that the image doesnt get siaplyed at all.
SINGLE_IMAGE_UPLOAD_NAME is a constant for the array key in $_FILES.
EDIT:
Not really a solution, but I changed to use the method to display images in this question and now it works:
how to display images from database in php?
Related
I have a json post that uploads photos. It works just fine. I want to change the name of the uploaded file as it is uploaded. I know how to do that. I want to add a number to the end of the file name before the image type extension. I know how to do that. I want the number to increment by one for each new file when I upload multiple images at once. I cant do that :-( Here is what Im working with:
if (!file_exists($vendimagepath) ) {
mkdir($vendimagepath,0777,TRUE);
}
$valid_extensions = array('gif', 'png', 'jpeg', 'jpg');
$uploader = new FileUpload('uploadfile');
// Handle the upload
$result = $uploader->handleUpload($vendimagepath);
if (!$result) {
exit(json_encode(array('success' => false, 'msg' => $uploader->getErrorMsg())));
} else {
echo json_encode(array('success' => true));
$_SESSION['success']=true;
$path = $uploader->getFileName();
$vendimagepath= $vendimagepath.$path;
$result = $db -> query("INSERT into vendimages (vendregid, vendimagepath) VALUES ('$vendredig', '$path')");
$result = $db -> update("UPDATE registervendors SET images='1' WHERE regid = '$vendredig' AND username='$vendusername' ");
}
I inserted a variable under the if statement at the top $x=1; and then under the $uploader=new fileupload I added a while loop with $x++; and put that closing brace at the end of the script. It didnt work. It uploaded files but they all end up with the same number (1) . I know why. The script is called for each new file uploaded so $x=1 restarts each time and therefore $x++ is 1 each time.
Since you want to count across page loads, you should use your $_SESSION. Before the uploads start set:
$_SESSION['upload_index'] = 1;
Then do $_SESSION['upload_index']++ each time you get a new uploaded file.
I have an image that is sent from an iPad app to an SQL database. I can retrieve this image and display in a web page using the following php:
$img = base64_encode($row['photoData']);
echo "<img src=\"data:image/jpg;charset=utf8;base64, $img\"/>";
This displays fine. What I want to do now is put this image into a PDF document using FPDF however I am struggling to do this.
This:
$img = base64_encode($row['photoData']);
$pdf->Image($img);
give this error:
FPDF error: Image file has no extension and no type was specified:
So I tried this (although I realise I will then have to look at how to get the size of the image sorted):
$pdf->Image($img, 20, 20, 20, 20 'JPG');
which give me:
FPDF error: Missing or incorrect image file:
What is the correct way to do this?
Or would it be easier to temporarily save the image to the server and then place the saved image into the PDFdoc?
As mentioned in the comments above this is possible by using a stream ("data url") to hand over the image data to the fpdf library without writing physical files to disk:
<?php
// load the 'fpdf' extension
require('fpdf.php');
// just for demonstration purpose, the OP gets the content from a database instead
$h_img = fopen('img.jpg', "rb");
$img = fread($h_img, filesize('img.jpg'));
fclose($h_img);
// prepare a base64 encoded "data url"
$pic = 'data://text/plain;base64,' . base64_encode($img);
// extract dimensions from image
$info = getimagesize($pic);
// create a simple pdf document to prove this is very well possible:
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello Image!');
$pdf->Image($pic, 10, 30, $info[0], $info[1], 'jpg');
$pdf->Output();
If this is a good advice is another question, this is merely meant to prove that this is possible...
According to the Docs FPDF::Image accepts a filename as the first argument, not a binary blob.
If you want to use FPDF specifically, save the image to a temporary file first, and then pass that to FPDF::Image.
To do that, something like this should work:
$tmpFile = tempnam(sys_get_temp_dir(), 'fpdfimg');
if (file_put_contents($tmpFile, $row['photoData'])) {
$fpdf->Image($tmpFile);
// save/display image
unlink($tmpFile);
}
Alternatively, if you want to just serve the image as a PDF (with no other content) you could use Imagick:
$im = new \Imagick();
$im->readImageBlob($row['photoData']);
$im->setImageFormat('pdf');
header('Content-Type: application/pdf');
echo $im;
Since FPDF cannot use base64 data to produce images on the PDF, I would recommend saving the file to the disk permanently as opposed to writing a temp file for every PDF operation.
This will save you a lot of I/O overhead.
Assuming your table has unique photo_id or photo_name to accompany photoData then you can use something like this to create your images and use them in FPDF.
I will also assume you have a last_update and photo_extension column.
<?php
$path = '/path/to/fpdf/images/';
$filename = $row['photo_id'].'.'.$row['photo_extension'];
$filepath = $path.$filename;
// If a physical file is not available then create it
// If the DB data is fresher than the file then make a new file
if(!is_file($filepath) || strtotime($row['last_update']) > filemtime($filepath))
{
$result = file_put_contents($filepath, $row['photoData']);
if($result === FALSE)
{
die(__FILE__.'<br>Error - Line #'.__LINE__.': Could not create '.$filepath);
}
}
$pdf->Image($filepath);
If you plan on updating the photoData which is stored in your DB then you will have to make sure to also have a timestamp column and compare that timestamp against the filemtime($filepath) of the image on your disk.
Another solution for this ;)
Make a new php by copying and pasting this (piece of fpdf's code edited):
require('fpdf.php');
class DATAIMAGE extends FPDF
{
protected function _parsedata($file)
{
// Extract info from a JPEG file
$a = getimagesizefromstring($file);
if(!$a)
$this->Error('Missing or incorrect image file: '.$file);
if($a[2]!=2)
$this->Error('Not a JPEG file: '.$file);
if(!isset($a['channels']) || $a['channels']==3)
$colspace = 'DeviceRGB';
elseif($a['channels']==4)
$colspace = 'DeviceCMYK';
else
$colspace = 'DeviceGray';
$bpc = isset($a['bits']) ? $a['bits'] : 8;
return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$file);
}
}
Then call this php instead of fpdf.php in your main php.
You'll now be able to display an image simply by adding 'data' to the end of the function:
$pdf->Image($mysqlrow["blob"],0,0,40,0,'data');
in my php page I have <input type='file' name='aimage[]' id='aimage' />
and a snippet code to get this file as :
foreach($_FILES["aimage"]["tmp_name"] as $file)
{
/*** get the image info. ***/
if(is_uploaded_file($file) && getimagesize($file) != false){
$size = getimagesize($file);
/*** assign our variables ***/
$type = $size['mime'];
$imgfp = fopen($file, 'rb');
$size = $size[3];
// $name = $file['name'];
$maxsize = 99999999;
/*** check the file is less than the maximum file size ***/
//if($_FILES['aimage']['size'] < $maxsize )
// {
/*** connect to db ***/
$formvars['file'] = fread($imgfp, getimagesize($file));
Although using foreach, I got error as Warning: fread() expects parameter 2 to be long, array given in. what's cause of this error? How can I check only images uploaded to site and other files detected by code?
The error is caused by the second parameter of fread() : getimagesize($file)) which returns an array and not a long. getimagesize returns an array(width, height)
Maybe you want to use filesize($file) instead
From the getimagesize documentation:
Returns an array with up to 7 elements. Not all image types will
include the channels and bits elements.
Index 0 and 1 contains respectively the width and the height of the
image.
Note: Some formats may contain no image or may contain multiple
images. In these cases, getimagesize() might not be able to properly
determine the image size. getimagesize() will return zero for width
and height in these cases. Index 2 is one of the IMAGETYPE_XXX
constants indicating the type of the image.
Index 3 is a text string with the correct height="yyy" width="xxx"
string that can be used directly in an IMG tag.
mime is the correspondant MIME type of the image. This information can
be used to deliver images with the correct HTTP Content-type header:
Example #1 getimagesize() and MIME types
Basically what I have to do, is write a Image to the database.
As far as I understand the imagejpeg function - the output should be the plain image data, if the "string $filename" is not set or NULL.
But it does not, the only output is "1" (true)...
How do I get to the image data, without first storing the image in the filesystem and reloading it?
Here is my Code example:
// If it is the right filetype.
if ($_FILES[$dom_element]['type'] == 'image/jpeg' || $_FILES[$dom_element]['type'] == 'image/pjpeg') {
// Create the image recource.
$image_image = imagecreatefromjpeg($_FILES[$dom_element]['tmp_name']);
}
// Resize the image.
imagecopyresampled($image_image_p, $image_image, 0, 0, 0, 0, $image_new_width, $image_new_height, $image_width, $image_height);
// Write the image in the database (does not work this way -> output = "1")
mysql_select_db("$db_announcement");
$sql = "UPDATE announcement
SET announcement_guest_image_data = '" . addslashes(imagejpeg($image_image_p, NULL, $settings_image_quality)) . "',
announcement_guest_image_exists = 'yes'
WHERE announcement_timestamp = '$timestamp' AND announcement_guest_mail = '$global_mail'";
$sql = mysql_query($sql);
// Delete the image recources.
imagedestroy($image_image);
imagedestroy($image_image_p);
The documentation says about the $filename parameter:
If not set or NULL, the raw image stream will be outputted directly.
And about the return value:
Returns TRUE on success or FALSE on failure.
The function outputs the image to the standard output. It does not return it.
You can capture it from the standard output like so:
ob_start();
imagejpeg(...);
$imageData = ob_get_clean();
I would highly recommend you to avoid storing binary data, such as images in database. You can simply record everything, including the image name, date of creation, etc. on your tables, then just put that file on the file system.
I know that it is not the answer you're looking for, however I thought that it might helps.
I'm having a problem getting my images to display after extracting them from a database.
I have 2 separate tables, one for the meta data and another to hold the actual blob data. that table is a regular BLOB and i only store 60k chunks of data in each row. I recompile the image when i want to render it.
i keep getting this error though:
the image "http://imgStore.localhost/ImageBuilder/index/id/11" cannot be displayed because it contains errors.
here is how the flow works however.
/Images/image/id/11 will have an image inside of it like this
<img src="http://imgStore.localhost/ImageBuilder/index/id/11" />
the Images controller handles insertions and edits as well as listing the images
while ImageBuilder is only concerned with displaying a given image
here is the table structure:
images ------
image_id INT
image_name VARCHAR
image_type VARCHAR
image_size INT
loaded_date DATETIME
image_data --
image_data_id INT
image_id INT
data BLOB
here is how i save the file into the database:
( NOTE: i'm using the latest Zend Framework )
( insertion action ) ------------------
$image = new ImgStore_Model_Images($form->getValues());
$image->setImage_size(((int) substr($form->image_file->getFileSize(), 0, -2) * 1024));
$image->setImage_type($form->image_file->getMimeType());
$image->setLoaded_date(time());
$image->setLoaded_by($user->get('contacts_id'));
$mapper = new ImgStore_Model_ImagesMapper();
$image_id = $mapper->save($image);
// open the uploaded file to read binary data
$fp = fopen($form->image_file->getFileName(), "r");
$dataMapper = new ImgStore_Model_ImageDataMapper();
// loop through the file and push the contents into
// image data entries
while( !feof($fp) ){
// Make the data mysql insert safe
$binary_data = addslashes(fread($fp, 60000));
$data_entry = new ImgStore_Model_ImageData();
$data_entry->setImage_id($image_id);
$data_entry->setImage_data($binary_data);
$dataMapper->save($data_entry);
}
fclose($fp);
and here is how it is extracted:
(action) ------------------
$this->_helper->_layout->disableLayout();
// get the image meta data
$image_id = $this->_request->getParam('id', '0');
$mapper = new ImgStore_Model_ImagesMapper();
$info = $mapper->getInfo($image_id);
// build the image and push it to the view
$mapper = new ImgStore_Model_ImageDataMapper();
$this->view->image = $mapper->buildImage($image_id);
$this->view->name = $info->getImage_name();
$this->view->type = $info->getImage_type();
$this->view->size = $info->getImage_size();
(model) ------------------
public function buildImage($image_id)
{
// get the image data
$sql = "SELECT image_data
FROM image_data
WHERE image_id='$image_id'
ORDER BY image_data_id ASC";
$results = $this->_adapter->fetchAll($sql);
// piece together the image and return it
$image = NULL;
foreach( $results as $row ){
$image .= $row['image_data'];
}
return $image;
} #end buildImage function
(view) ------------------
<?php
header( "Content-Type: " . $this->type );
header('Content-Disposition: inline; filename="'.$this->name.'"');
echo $this->image;
?>
i have tried to use an image that was small enough to take up only one row in the image_data table as well, so i don't believe it has anything to do with the recompilation of the image_data rows.
any help would be appreciated, i truly have no idea what is wrong with this.
edited some formatting for display purposes.
I recently did something like this but used a different approach for the rendering. Zend won't fire up the app if the request URI to an actual file, so I created a render action in my file controller that created a copy of the image on the drive. This makes scaling and management much easier since the files are all in one central db, but also gives the performance benefits of reading from the disk. Here's my open action:
public function openAction() {
$file = // find the file in the db
if(! $file) {
throw new Zend_Exception('File not found', 404);
}
$path = // get the filepath
if(! file_exists($path) || $this->_request->getParam('reload') == true) {
file_put_contents($path, $file->image_data);
}
$this->_redirect('document root relative path');
}
there's no real value in cluttering up the database with image data. (Fetching the data from the database will also be significantly slower than simply loading it off disk)
I suggest that you just store the images on the file system, and store the path to the image in the database alongside the meta data.