PHP copy/rename from FTP folder corrupts files when upload is in progress 
This took weeks to troubleshoot so maybe I can save you some time by relating the experience...

I have an application that reads files from a FTP drop folder and moves them to a queue folder. If the move is successful, a queue record is put into the database.

Now, you would have thought that is_file() would have been enough to detect if a file was ready (ie: not still being uploaded by a user). As it happens, the FTP server is 'clever' enough to give you read access during the upload, allowing you to see its progress. And so my queue script was copying and unlinking files that were incomplete.

So, I tried is_readable() - same thing.
Then I added is_writeable() - you'd think this would do it. Surely files were locked during an upload? Nope, same problem.
Then I tried doing a filesize() followed by a sleep then another filesize() and compared them. Didn't work. Then I added a filesize() > 0 check. No joy. I also made sure the stat data wasn't being cached by calling clearstatcache() each time. No difference.

Finally, the only thing that seemed to work (and yes I am still uncertain the problem has completely gone away!) is comparing a stat() on the file with a sleep() in between.

Anyway, here's the final moveFile function that appears to be working for now...

protected function moveFile($from, $to){
clearstatcache();
$this->write2log("Called moveFile ".$from. " > ".$to);
$this->write2log("File ".basename($from). " is " . intval(filesize($from)/(1024*1024/100))/100 ."MB");

if (is_file($from)){
if (is_readable($from)){
if (is_writable($from)){
//check for filesize change
$size = filesize($from);
$stat = stat($from);
sleep(5);
clearstatcache();
if ($size == filesize($from) && $size > 0 && $stat == stat($from)){
if (copy($from, $to)){
if (unlink($from)){
$this->write2log("Successfully moved ".$from. " > ".$to);
return true;
}
$this->write2log("FAILED to unlink ".$from);
}
$this->write2log("FAILED to copy ".$from. " > ".$to);
}
$this->write2log("UPLOAD IN PROGRESS ".$from);
}
$this->write2log("NOT WRITABLE ".$from);
}
$this->write2log("NOT READABLE ".$from);
}
$this->write2log("NOT A FILE ".$from);
return false;
}

  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 3 / 56 )
MySQL Workbench 
Nice little app for building MySQL databases under windows...
  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 2.8 / 79 )
Symfony build model errors (revised) 
If you reverse engineer your Symfony schema.yml from a database and you use the symfony plugins like sfGuard, chances are you've come across this error:

Duplicate table found: propel

The reason why this occurs is that your schema.yml will include the other plugin tables - which are now duplicated from the plugin schema.yml

The quick solution is to open your project database.yml and remove the plugin table definitions after running propel-build-schema and before running propel-build-model

If you make a lot of database changes you might want to either empty/remove the plugin schema.yml file (it's only needed for the initial installation anyway) or write a wrapper class for propel... :)
  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 3 / 60 )
The best lightbox script just got better 
Ever wanted to load a PDF file inline? Maybe in a lightbox window? Well now you can. Michael J.I. Jackson's "thrilling" shadowbox loads all your media files, HTML pages etc with lovely effects sourced from prototype, scriptaculous, yahoo, mootools or your other AJAX library of choice. It does it using adapters and it is the slickest GUI enhancer I've seen yet.

But lo and behold it doesn't support acrobat PDF documents!
Well, it does if you make one very tiny change to the source code:

Add " pdf" to the iframe array like so...

iframe:["pdf","asp","aspx","cgi","cfm","htm","html","pl",
"php","php3","php4","php5","phtml","rb","rhtml","shtml","txt",
"vbs"]


Now it loads PDF files just like your HTML pages in an IFRAME with all the benefits of the lightbox transitions, loading animation, navigation, captions etc
  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 3 / 64 )
DIY Symfony Propel Hydration with Pager 
It's a typical scenario - I have a search module that returns a bunch of objects that have related objects (and some of these have related objects as well).

Ordinarily, you'd use a doSelectJoinAll and let propel magically hydrate all your results - but that only works for parent objects, not child objects.

So, rather than looping over each object and running separate queries to get each objects child objects, I wanted to do the equivalent of a doSelectJoinAll() but fully hydrate all the results with a minimum number of queries. Here's how I did it...

Query 1 retrieves all the IDs of the matching records.

Each of these search results has a location
Each location has a category

Query 2 gets all the locations using Criteria::IN on all result IDs.
Query 3 gets all the categories using Criteria::IN on all location IDs.

Then I loop over the results of queries 2 and 3 and build the collections of results like so:

foreach ($results as $r) { $rs[$r->getResultId()]->addCollItem("ResultLocations",$r->getLocation());
}


This nifty bit of code calls the following class function:

function addCollItem($type,$item)
{
$init = "init".$type;
$property = "coll".$type;
if (!method_exists($this,$init)){
$this->$property = array();
}else{
$this->$init();
}

$class_property = $this->$property;
$class_property[] = $item;
}


Whammo! You get to feed related objects into the master object's protected collections :)
  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 3 / 55 )
Javascript ParseInt("08"); 
I thought I'd seen it all until today. JavaScript is so "intelligent" that if you try to ParseInt() on "08" you get 0. Why? Because it thinks you're speaking in octal (base 8 numbers) instead of decimal (base 10).

The solution is to either use parseFloat() or to force the use of decimal by passing 10 as the second parameter to parseInt().
  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 3 / 64 )
PHP File downloads - beware the multibyte encoding! 
Took me a day to work out why my fread() file transfers were failing - at almost exactly half way. It got me thinking - perhaps the output was being compressed. I turned off mod_deflate. Same problem. Then I started looking at the PHP buffer because I was doing something like this:

while(!feof($handle)){
set_time_limit(0);
print(fread($handle,1024*8));
ob_flush();
flush();
}


Then I checked the output handler and realised there was some multibyte encoding taking place, which was the key. This has to be turned off for binary data like so:

mb_http_output("pass");

Seems strange noone has mentioned this on the PHP site under fread() - so I did.

  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 2.9 / 63 )
CSS Hacks - Firefox + IE6 + IE7 
You know when you're entering the final phase of user testing when you need to fine tune style sheets for multiple browsers. This appears to be the final word on getting identical pages in FF, IE6 and IE7 and I thought I'd share it...

#MyDiv {
margin : 10px 10px 10px 10px;
}

/* IE6 Only */
* html #MyDiv {
margin : 5px 5px 5px 5px;
}

/* IE7 Only */
*:first-child+html #MyDiv {
margin : 2px 2px 2px 2px;
}

  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 2.8 / 99 )
PNG Transparency - the final fix 
I have been using the PNG filter trick in IE6 for over a year now, but recently had to remove it from a very GUI intensive project as it was maxing out the CPU on older clients. So I went looking (again) for the prefect solution.

Option 1 - PHP Browser checking

This was very effective - run all image requests through a PHP page using mod_rewrite. Then get the PHP page to do a user agent test and spit out a GIF if the browser is IE < 7 and the image is a PNG. The downside is that every image is being returned via a PHP readfile() which is *very* inefficient.

Alternatively, adjust the mod_rewrite rule to only redirect PNG files, but then you're still using PHP to do what Apache does much better....

Option 2 - mod_rewrite condition

The ultimate... use apache to selectively redirect IE5/6 to GIF files for each PNG file served. Easy. Move the responsibility to the server. And here it is...

RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_USER_AGENT} MSIE\s(5|6)
RewriteRule ^(.*)png$ $1gif [R]


All you have to do is batcg convert your PNG files to GIF files with the same name. You can even put them in a seperate folder if you need to...

  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 3 / 55 )
Prototype 1.6 - IE bug: element.getOffsetParent throws errors 
It's only a workaround, but it's widely recognised as a bug. So for now you can wrap a try statement around line 2082 like so:

getOffsetParent: function(element) {
try{
if (element.offsetParent) return $(element.offsetParent);
}catch(e){}
if (element == document.body) return $(element);

while ((element = element.parentNode) && element != document.body)
if (Element.getStyle(element, 'position') != 'static')
return $(element);

return $(document.body);
},

  |  [ 0 trackbacks ]   |  permalink  |  related link  |   ( 2.9 / 54 )

Back Next