August 22, 2007

PHP File Upload Woes

You will find other articles relevant to this document in these sections:
Richard Lee @ 11:51 am

I’ve spent the last 2 days trying to get a file uploading script working on my shared host. It’s driving me crazy. Files 1MB and under upload completely fine, but anything above and the browser bombs out with “server busy..” errors! Before you say “update your max_upload_size, post_max_size and max_execution_time ini settings“. Forget it. Been there done that. No success. Is Apache overriding my settings? Some investigation into the possibility has unveiled 4 possibilities. The Apache directives LimitReqestBody, TimeOut, RLimitMEM and RLimitCPU. I’ve read that LimitRequestBody will limit the size of the incomming request, and TimeOut is pretty self explanatory. Still reading into the affects of RLimit*.

If you’ve experienced php upload problems and can offer any insight please let me know! Anyway i’ll keep you posted on further developments on the issue..

UPDATE:
Ok it seems my server tweaks were not the problem, it’s actually Firefox timing out. IE after some time eventually uploads the file as expected. The file is being uploaded at roughly 1 minute per MB over our broadband connection, and FF seems to be bomb out after 2 and half minutes. There seems to be some tweaks in the FF about:config that can me made just not sure what yet!
(for the record i am testing in FF 2.0.0.5 and IE 7 on XP)

August 17, 2007

Multiple INSERT’s in MySQL

You will find other articles relevant to this document in these sections:
Richard Lee @ 12:04 pm

Did you know you can actually do multiple record inserts in one mysql query? Well, since version 3.22.5 anyway… Just group each value set in parenthesis and seperate via commas - and bobs your uncle!

< ?php
 
$query = "INSERT INTO results (firstname, lastname, score) 
VALUES 
 ('joe', 'bloggs', 77),
 ('mary', 'jane', 80),
 ('matthew', 'heinze', 60)";
 
mysql_query($query);
 
?>

August 13, 2007

PHP File Manipulation on Apache

You will find other articles relevant to this document in these sections:
Richard Lee @ 3:36 pm

Without a doubt the biggest “gotcha” when working with files in PHP is permissions. Simply put in order for any PHP script to write to a file the Apache needs to have privileges to that file. This can be a bit of an issue in a shared hosting environment especially. Your webhost maybe running Apache under one user and for manipulating files and directories you are required to use FTP or shell which operates under a different user. So how can you make sure you have the correct permissions? First port of call is definitely your webhost. They should indicate in their support information the permissions required in order for your PHP scripts to write to a file on the server. For most it will be 777, which means EVERYONE has read/write/execute access - so be weary sensitive files may be accessible!

How to set permissions on your webserver:

1. Using FTP:

Probably the easiest way of setting permissions is through an FTP Application (Eg Core FTP & Filezilla). Usually it’s simply a matter of right-clicking and entering the numeric permission (777) or checking the correct boxes for “Owner” “Group” and “Other” (all for 777). You may also be able to recursively set permissions on any child files.
2. Through Linux Shell:

Linux shell is a little more advanced, offering a few more options but not all webhosts offer shell access. If you do have shell access you can run the chmod command followed by the numeric permission like so:

$ chmod 777 uploads

Additional options are set by passing -flags. For example for recursive permission setting of the uploads directory:

$ chmod -R 777 uploads

3. In PHP script:

A number of PHP functions allow you to set file permissions on the fly. However, to do this Apache needs to have permission to write to the parent directory in the first place! Here are some examples:

Creating a directory with 777 permissions -

// Under Linux
mkdir('/absolute/path/to/uploads/images', 0777); // beginning '/' is important!
// Under Windows
mkdir('E:/absolute/path/to/uploads/images', 0777); // windows has driver name instead of beginning slash
// Creating a directory recursively
// (see below)

(note: mkdir() actually sets directories to 777 by default)

Setting an image file to 777 so we can manipulate it with PHP’s various image functions -

chmod('/absolute/path/to/uploads/images/pic_thumb.jpg', 0777);

Getting around open_basedir restrictions

One little speedhump I discovered recently was the effect of open_basedir restrictions on directory creation. I was creating a directory tree recursively by passing the absolute path, then splitting it up into directories and creating each directory incrementally based on whether is existed or not.

$folder = preg_split( "/[/]/" , '/absolute/path/to/uploads/images' );
// append beginning slash for Linux
$mkfolder =  strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' ? '' : DIRECTORY_SEPARATOR;
for(  $i=0 ; isset( $folder[$i] ) ; $i++ )
{
if(!strlen(trim($folder[$i])))continue;
$mkfolder .= $folder[$i];
if( !is_dir( $mkfolder ) ){
mkdir( "$mkfolder" ,  0777);
}
$mkfolder .= DIRECTORY_SEPARATOR;
}

Problem was being an absolute path some of the directories were outside of the webroot and PHP was unable to run any checks on the directories due to permissions! The solution was to do the checks using shell instead via PHP’s exec() function so i created by own is_dir function open_basedir_is_dir():

// open_basedir safe is_dir function
function open_basedir_is_dir($dir) {
 
// get base_dir settings
$open_basedir = @ini_get('open_basedir');
 
// if open_basedir has  not been set we'll use normal check
if (empty($open_basedir)) {
return is_dir($dir);
} else {
// run shell command
exec("ls -dl $dir", $tmp_cmd);
// if nothing set assuming dir doesn't exist, or if not "d" flag its not a dir
// [d] directory [l] link [-] regular file)
return (isset($tmp_cmd[0]) && substr($tmp_cmd[0], 0, 1) == 'd');
}
}
 
$folder = preg_split( "/[/]/" , '/absolute/path/to/uploads/images' );
// append beginning slash for Linux
$mkfolder =  strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' ? '' : DIRECTORY_SEPARATOR;
for(  $i=0 ; isset( $folder[$i] ) ; $i++ )
{
if(!strlen(trim($folder[$i])))continue;
$mkfolder .= $folder[$i];
if( !open_base_dir_is_dir( $mkfolder ) ){
mkdir( "$mkfolder" ,  0777);
}
$mkfolder .= DIRECTORY_SEPARATOR;
}