One area in KnowledgeTree that gets a few problem reports is that of file uploads. Of course, being a document management system, it's rather important that KnowledgeTree handle this well.
Last time, I using .htaccess to make KnowledgeTree usable on more systems. In there, a few settings are really important:
LimitRequestBody 0 php_value upload_max_filesize 16M php_value post_max_size 16M php_value memory_limit 16M
I've since discovered that you can't set file_uploads in .htaccess, only in php.ini, but it's still important.
The easy ones first, as well as general file upload handling etiquette in PHP.
if (!$fStore) {
// some other stuff
exit(0);
}
// make sure the user actually selected a file first
// and that something was uploaded
if (!((strlen($_FILES['fFile']['name']) > 0) && $_FILES['fFile']['size'] > 0)) {
// no uploaded file
require_once("$default->fileSystemRoot/presentation/webpageTemplate.inc");
$oPatternCustom = & new PatternCustom();
$message = _("You did not select a valid document to upload");
$errors = array(
1 => _("The uploaded file is larger than the PHP upload_max_filesize setting"),
2 => _("The uploaded file is larger than the MAX_FILE_SIZE directive that was specified in the HTML form"),
3 => _("The uploaded file was not fully uploaded to KnowledgeTree"),
4 => _("No file was selected to be uploaded to KnowledgeTree"),
6 => _("An internal error occurred receiving the uploaded document"),
);
$message = KTUtil::arrayGet($errors, $_FILES['fFile']['error'], $message);
if (@ini_get("file_uploads") == false) {
$message = _("File uploads are disabled in your PHP configuration");
}
$oPatternCustom->setHtml(getStatusPage($fFolderID, $message . "</td><td><a href=\"$default->rootUrl/control.php?action=addDocument&fFolderID=$fFolderID&fDocumentTypeID=$fDocumentTypeID\"><img src=\"" . KTHtml::getBackButton() . "\" border=\"0\"></a>")); $main->setCentralPayload($oPatternCustom);
$main->render();
exit(0);
}
By the time it gets to the code in question, we're sure that the user intended to upload a file. But if either a filename is not given, or the file size is zero, we have a problem of some sort (actually, some people want to upload zero-byte files...).
Anyway, we default to some generic message, and then look up the error code from the file upload error variable (as described in the file upload errors section of the PHP manual). Then, we make sure we are even able to do file uploads in PHP. And give some error message.
Ok, that covers upload_max_filesize and file_uploads, and any normal upload problem (partial uploads, no file given), and I imagine there is a good file uploading class in PEAR or on phpclasses for this.
But? What about post_max_size? PHP does something interesting for this. If the POST value is too big, it seems it simply pretends there was no POST in the first place. So, suddenly the URL you were posting to is accessed as if there was a GET request to that URL. Intriguing behaviour, if you don't have display_startup_errors set. But ultimately, I would like to run without it on, and it's actually rather easy to deal with this.
Since the URL you're POSTING to can include GET variables, we can set a GET variable, such as postExpected. Then, if we see postExpected in our code, we know we were supposed to have a POST done to us. And then, we can set a hidden variable in our form, say postReceived. And then if postExpected is there, and postReceived is not, we can be pretty sure post_max_size was violated. And then we can give an error message. Like this:
$postExpected = KTUtil::arrayGet($_REQUEST, "postExpected");
$postReceived = KTUtil::arrayGet($_REQUEST, "postReceived");
if (!is_null($postExpected) && is_null($postReceived)) {
// A post was to be initiated by the client, but none was received.
// This means post_max_size was violated.
require_once("$default->fileSystemRoot/presentation/webpageTemplate.inc");
$oPatternCustom = & new PatternCustom();
$errorMessage = _("You tried to upload a file that is larger than the PHP post_max_size setting.");
$oPatternCustom->setHtml(getStatusPage($fFolderID, $errorMessage . "</td><td><a href=\"$default->rootUrl/control.php?action=browse&fFolderID=$fFolderID\"><img src=\"" . KTHtml::getCancelButton() . "\" border=\"0\"></a>"));
$main->setCentralPayload($oPatternCustom);
$main->render();
exit(0);
}
I'd love to know if someone knows of a good, reliable, file upload class that I can use, that'll detect all the usual problems. And also if there is some other way of detected post_max_size being violated.
Until then, this seems to work fine, and hopefully I'll get less support requests on this issue.
2 old-style comments
leon breedt — May 28, 2005 at 02:20 PM.
Neil Blakey-Milner — May 28, 2005 at 02:23 PM.