3

I am looking to flock() an image.

Currently I am using the following

$img = ImageCreateFromPng($img_path);
flock($img,LOCK_EX);

It seems that the GD library's file handle is not valid with flock. How can I access the image and flock the file?

Pablo
  • 4,273
  • 7
  • 33
  • 34

3 Answers3

1

The function flock only works on file handles (or stream wrappers if they support locking). So, if you want to lock an image when you read it, you'd need to open it twice:

$f = fopen($imgPath, 'r');
if (!$f) {
    //Handle error (file does not exist perhaps, or no permissions?)
}
if (flock($f, LOCK_EX)) {
    $img = imagecreatefrompng($imgPath);
    //...  Do your stuff here

    flock($f, LOCK_UN);
}
fclose($f);
ircmaxell
  • 163,128
  • 34
  • 264
  • 314
  • hmmm, IF the image is flock'd then I get an error from imagecreatefrompng - saying that it is not a valid png. To test it just before I called imagecreatefrompng I called flock($f, LOCK_UN) and the code worked again. – Pablo Jun 15 '10 at 13:10
  • I am using it on Windows at the moment. But this is only for testing.... it will be live on a linux server. – Pablo Jun 15 '10 at 13:48
  • That's probrably why. Windows has internal locking that prevents opening a file for write while another processes has it open. It should work fine on Linux, for what it's worth (And not have the memory overhead of reading the file in a string in PHP)... – ircmaxell Jun 15 '10 at 13:57
1

$img in your example is not a file handle, it is a handle to a GD image resource in memory.

You can use imagecreatefromstring to load an image like this:

$file=fopen($fileName,"r+b");
flock($file,LOCK_EX);
$imageBinary=stream_get_contents($file);
$img=imagecreatefromstring($imageBinary);
unset($imageBinary); // we don't need this anymore - it saves a lot of memory

If you want to save a modified version of the image to the open stream you have to use output buffering:

ob_start();
imagepng($img);
$imageBinary=ob_get_clean();

ftruncate($file,0);
fseek($file,0);
fwrite($file,$imageBinary);
unset($imageBinary);
flock($file,LOCK_UN);
fclose($file);
Wikeno
  • 419
  • 2
  • 4
  • This looks like a good workaround to the problem of imagecreatefrompng not working on flocked files. – Edward Dale Jun 15 '10 at 13:19
  • I get an error for a parameter missing for ftruncate... I looked it up seems to be the size that you wish to truncate the file by – Pablo Jun 15 '10 at 13:26
  • I haven't tested it so you may also have to fseek($file,0) after the trucating. – Wikeno Jun 15 '10 at 13:38
  • I tried truncating it to 0... it generated a file twice the size of the original... I'll try fseek – Pablo Jun 15 '10 at 13:49
  • Hmmm.. I just benchmarked it. This takes 600ms... imagecreatefrompng,imagepng ... takes 0.12ms. I am not sure its a viable option :S Thanks anyway – Pablo Jun 15 '10 at 13:55
0

flock only works with file pointers and ImageCreateFromPng only works with filenames. Try making two different calls:

$fp = fopen($img_path, 'r');
flock($fp, LOCK_EX);
$img = ImageCreateFromPng($img_path);

flock is cooperative, so it only works if everybody uses it. As long as ImageCreateFromPng doesn't use flock, the code above should work.

Edward Dale
  • 29,597
  • 13
  • 90
  • 129
  • hmmm, If the image is flock'd then I get an error from imagecreatefrompng - saying that it is not a valid png. To test it just before I called imagecreatefrompng I called flock($fp, LOCK_UN) and the code worked again. – Pablo Jun 15 '10 at 13:11
  • That's too bad. Maybe try locking the file and copying it to a temporary file. Then, operate on the temporary file while the main file is locked. – Edward Dale Jun 15 '10 at 13:18
  • Thanks, ircmaxell assures me that it will work on linux... so i'll be using this method after all. – Pablo Jun 15 '10 at 14:06