Web студия "GrandView"
  Главная   Написать Контакты
   
   
О проекте
Руководство php
 

Глава 38. Загрузка файлов на сервер

Загрузка файлов методом POST

PHP способен принимать файл загружаемый при помощи любого браузера, поддерживающего стандарт RFC-1867 (в том числе Netscape Navigator 3 и выше, Microsoft Internet Explorer 3 с патчем от Microsoft или более поздние версии без патча). Это дает возможность загружать как текстовые, так и бинарные файлы. Вместе с PHP-аутентификацией и функциями для работы с файловой системой вы получаете полный контроль над тем, кому разрешено загружать файлы, и над тем, что делать с файлом после его загрузки.

Смежные замечания по конфигурации: Также ознакомьтесь с описанием директив file_uploads, upload_max_filesize, upload_tmp_dir, max_input_time и post_max_size конфигурационного файла php.ini

Также следует заметить, что PHP поддерживает загрузку файлов методом PUT, который используется в клиентах Netscape Composer и W3C Amaya. Для получения более детальной документации обратитесь к разделу поддержка метода PUT

Страница для загрузки файлов может быть реализована при помощи специальной формы, которая выглядит примерно так:

Пример 38-1. Форма для загрузки файлов

<form enctype="multipart/form-data" action="_URL_" method="post">
 <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
 Отправить этот файл: <input name="userfile" type="file" />
 <input type="submit" value="Send File" />
</form>

В приведенном выше примере "_URL_" необходимо заменить ссылкой на PHP-скрипт. Скрытое поле MAX_FILE_SIZE(значение необходимо указывать в байтах) должно предшествовать полю для выбора файла, и его значение является максимально допустимым размером принимаемого файла. Также следует убедиться, что в атрибутах формы вы указали enctype="multipart/form-data", в противном случае загрузка файлов на сервер выполняться не будет.

Внимание

Опция MAX_FILE_SIZE является рекомендацией браузеру, даже если бы PHP также проверял это условие. Обойти это ограничение на стороне браузера достаточно просто, следовательно, вы не должны полагаться на то, что все файлы большего размера будут блокированы при помощи этой возможности. Тем не менее, ограничение PHP касательно максимального размера обойти невозможно. Вы в любом случае должны добавлять переменную формы MAX_FILE_SIZE, так как она предотвращает тревожное ожидание пользователей при передаче огромных файлов, только для того, чтобы узнать, что файл слишком большой и передача фактически не состоялась.

Переменные, определенные для загруженных файлов, зависят от версии PHP и текущей конфигурации. Суперглобальный массив $_FILES доступен начиная с PHP 4.1.0. Массив $HTTP_POST_FILES доступен начиная с PHP 4.0.0. Эти массивы содержат всю информацию о загруженных файлах. Использование $_FILES является более предпочтительным. В случае, если конфигурационная директива register_globals установлена значением on, дополнительно будут объявлены переменные с соответствующими именами. Начиная с версии 4.2.0 значением по умолчанию для опции register_globals является off.

Содержимое массива $_FILES для нашего примера приведено ниже. Обратите внимание, что здесь предполагается использование имени userfile для поля выбора файла, как и в приведенном выше примере. На самом деле имя поля может быть любым.

$_FILES['userfile']['name']

Оригинальное имя файла на компьютере клиента.

$_FILES['userfile']['type']

Mime-тип файла, в случае, если браузер предоставил такую информацию. Пример: "image/gif".

$_FILES['userfile']['size']

Размер в байтах принятого файла.

$_FILES['userfile']['tmp_name']

Временное имя, с которым принятый файл был сохранен на сервере.

$_FILES['userfile']['error']

Код ошибки, которая может возникнуть при загрузке файла. Ключ ['error'] был добавлен в PHP 4.2.0

Замечание: В PHP 4.1.0 и более ранних версиях описанный выше массив назывался $HTTP_POST_FILES и не являлся суперглобальным, в отличие от $_FILES. В PHP 3 массив $HTTP_POST_FILES не определен.

В случае, если register_globals установлена значением on в конфигурационном файле php.ini, будут доступны дополнительные переменные. Например, $userfile_name будет эквивалентна переменной $_FILES['userfile']['name'], а $userfile_type соответствует $_FILES['userfile']['type'], и так далее. Не стоит забывать, что начиная с PHP 4.2.0 для директивы register_globals значение по умолчанию off. Рекомендуется не полагаться на значение этой директивы.

По умолчанию принятые файлы сохраняются на сервере в стандартной временной папке до тех пор, пока не будет задана другая директория при помощи директивы upload_tmp_dir конфигурационного файла php.ini. Директорию сервера по умолчанию можно сменить, установив переменную TMPDIR для окружения, в котором выполняется PHP. Установка переменной TMPDIR при помощи функции putenv() внутри PHP-скрипта работать не будет. Эта переменная окружения также может использоваться для того, чтобы удостовериться, что другие операции также работают с принятыми файлами.

Пример 38-2. Проверка загружаемых на сервер файлов

Для получения более детальной информации вы можете ознакомится с описанием функций is_uploaded_file() и move_uploaded_file(). Следующий пример принимает и обрабатывает загруженный при помощи формы файл.

<?php
// В PHP 4.1.0 и более ранних версиях следует использовать $HTTP_POST_FILES
// вместо $_FILES.

$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

print
"<pre>";
if (
move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
    print
"File is valid, and was successfully uploaded. ";
    print
"Here's some more debugging info:\n";
   
print_r($_FILES);
} else {
    print
"Possible file upload attack!  Here's some debugging info:\n";
    print
"Possible file upload attack!  Дополнительная отладочная информация:\n";
   
print_r($_FILES);
}
print
"</pre>";

?>

PHP-скрипт, принимающий загруженный файл, должен реализовывать логику, необходимую для определения дальнейших действий над принятым файлом. Например, вы можете проверить переменную $_FILES['userfile']['size'], чтобы отсечь слишком большие или слишком маленькие файлы. Также вы можете использовать переменную $_FILES['userfile']['type'] для исключения файлов, которые не удовлетворяют критерию касательно типа файла. Начиная с PHP 4.2.0 вы можете использовать $_FILES['userfile']['error'] и разъяснение сообщений об ошибках при реализации вашей логики. Независимо от того, какую модель поведения вы выбрали, вы должны удалить файл из временной папки или переместить его в другую директорию.

В случае, если при отправке формы файл выбран не был, PHP установит переменную $_FILES['userfile']['size'] значением 0, а переменную $_FILES['userfile']['tmp_name'] - пустой строкой. none.

По окончанию работы скрипта, в случае, если принятый файл не был переименован, или перемещен он будет автоматически удален из временной папки.



add a note add a note User Contributed Notes
Загрузка файлов на сервер
ragtime at alice-dsl dot com
26-Sep-2007 07:59
OK,... I got it... finally!

If some of you have also problems uploading large files but the usual sizes/times in php.ini are ok, please check

    session.gc_maxlifetime

when you are using session management with your upload script!

The default value is 1440 which is just 24min... so with only 600kbit/s upload rate the session will be closed automatically after uploading
about 100MB. Actually you are able to upload more, but the file won't be copied from the temporary to the destination folder... ;-)

You can set the value also directly inside the php-script via
<? ini_set("session.gc_maxlifetime","10800"); ?>
ragtime at alice-dsl dot com
24-Sep-2007 08:55
I don't believe the myth that 'memory_size' should be the size of the uploaded file. The files are definitely not kept in memory... instead uploaded chunks of 1MB each are stored under /var/tmp and later on rebuild under /tmp before moving to the web/user space.

I'm running a linux-box with only 64MB RAM, setting the memory_limit to 16MB and uploading files of sizes about 100MB is no problem at all! Nevertheless, some users reported a problem at a few 100MB, but that's not confirmed... ;-)

The other sizes in php.ini are set to 1GB and the times to 300... maybe the execution_time limits before, since the CPU is just a 233MHz one... :-)
HNS
12-Sep-2007 01:30
I rather check the imagetype with getimagesize. <4 and != 0 equals jpg, gif, png. Also it already gives you a chance to store other interesting data about the images.
php.ini vars that deal with size that need to be checked are
-max upload filesize
-max post data size
-memory limit (for script to use)
My suggestion is to keep the two latter greater then the upload file size limit to be able to give back some user errors.
When POST data size get exceeded it just doesn't run the script that is set to run at application of a form. So
ash at atomic-network dot co dot uk
09-Sep-2007 03:51
I have always wanted to just allow image files; and found using an array which would work on IE, FF, And Opera etc.
would be to define the "image/name" for all of those.
as IE is "image/x-name" and FF is "image/name" etc.

<?php
function  image_valid($type)
{
   
$file_types  = array(  
   
'image/pjpeg'     => 'jpg',
   
'image/jpeg'     => 'jpg',
   
'image/jpeg'     => 'jpeg',
   
'image/gif'     => 'gif',
   
'image/X-PNG'    => 'png',
   
'image/PNG'         => 'png',
   
'image/png'     => 'png',
   
'image/x-png'     => 'png',
   
'image/JPG'     => 'jpg',
   
'image/GIF'     => 'gif',
   
'image/bmp'     => 'bmp',
   
'image/bmp'     => 'BMP',
    );
   
    if(!
array_key_exists($type, $file_types))
    {
        return
"FALSE";
    }
    else
    {
        return
"TRUE";
    }
}

if(
image_valid($_FILES['user_file']['type']) === "FALSE")
{
    die(
"Image file is not valid");
}
?>
v dot galyanin at gmail dot com
21-Jul-2007 03:37
I try to set up file uploading under IIS 7 and PHP 5.

First problem was to set 2 variables in php.ini

 file_uploads = On

 upload_tmp_dir = "C:\Inetpub\wwwroot\uploads"

 For some reasons such directory name works,
 but "upload_tmp" won't work.

The second problem was to set correct user rigths for upload folders where you try to save your file. I set my upload folder rights for the "WORKGROUP/users" for the full access. You may experiment by yourselves if you not need execute access, for example.
burn dot wang at gmail dot com
20-Jul-2007 04:03
[uploadprogress] PECL ext has a critical bug on the win32 platform, http://pecl.php.net/bugs/bug.php?id=9584
There is a fixed version on
http://www.emforge.org/wiki/AjaxBasedFileUploadForPHP

It appeared to be working on my Winxp-sp2,
Thank you akakunin
sogdiev at gmail dot com
10-Jul-2007 01:19
Hi there.
As far as I understand IE has his own MIME types based on the values stored in a registry. To locate this "feature" I spent a lot of time and was granted with a perfect headache. :)
In my case I tried to upload a CSV file on a server and abort a script in case if the corresponding file isn't of a desired type.
And it work fine with Opera and stuck with IE.
So the workaround is that you should add this values in your windows registry (I have windows xp box and it works fine for me)
[HKEY_CLASSES_ROOT\.csv]
"Content Type"="application/vnd.ms-excel"
@="Excel.CSV"
[HKEY_CLASSES_ROOT\.csv\Excel.CSV]
[HKEY_CLASSES_ROOT\.csv\Excel.CSV\ShellNew]

NB:
add the value "application/vnd.ms-excel" if you plan to open it with excel.
Richard Davey rich at corephp dot co dot uk
21-Jun-2007 05:05
Beware the mime-types! Given the GIF security issue that has been doing the rounds recently you may be inclined to validate an update based on its reported mime-type from the $_FILES array. However be careful with this - it is set by the *browser*, not by PHP or the web server, and browsers are not consistent (what's new?!)

For example IE6/7 will upload a progressive JPEG as image/pjpeg, while Firefox and Opera will upload it as image/jpeg. More importantly IE will try and determine the mime type of the file by actually inspecting its contents. For example if you rename a perfectly valid PNG file to end with .zip instead, IE will still send a mime type of image/x-png, where-as Firefox and Opera will send application/x-zip-compressed and application/zip respectively, even though the file is a valid PNG.

In short if you are going to validate an upload on the mime-type, be sure to do some careful research and testing first!
djcassis gmail com
30-May-2007 08:33
Here is the fastest way to retreive an integer size from a value coming from your php.ini file :
<?php
function ini_get_size($sName)
{
   
$sSize = ini_get($sName);
   
$sUnit = substr($sSize, -1);
   
$iSize = (int) substr($sSize, 0, -1);
    switch (
strtoupper($sUnit))
    {
        case
'Y' : $iSize *= 1024; // Yotta
       
case 'Z' : $iSize *= 1024; // Zetta
       
case 'E' : $iSize *= 1024; // Exa
       
case 'P' : $iSize *= 1024; // Peta
       
case 'T' : $iSize *= 1024; // Tera
       
case 'G' : $iSize *= 1024; // Giga
       
case 'M' : $iSize *= 1024; // Mega
       
case 'K' : $iSize *= 1024; // kilo
   
};
    return
$iSize;
}

// example
echo ini_get_size('post_max_size'); // e.g. 8388608 instead of 8M
?>
Let's just hope PHP will live long enough to see petabytes and yottabytes ;o)
Peter Clarke
25-May-2007 06:24
To clarify a point made by Brian AW:
"Turns out php stores the uploaded file in memory until you do something with it"
this is not true. The file is written to the tmp directory as it is uploaded (just keep checking your tmp directory whilst uploading to confirm this for yourself). I just uploaded an 111M file with php restricted to 8M of memory.
Chaos Mixed aka Chaosmixed
27-Apr-2007 05:22
To people with IIS and php on a windows XP machine:

Php.ini:
upload_tmp_dir = "C:\Inetpub\wwwroot\upload_tmp\"

then create two folder in the wwwroot directory:
C:\Inetpub\wwwroot\upload
C:\Inetpub\wwwroot\upload_tmp

Make sure sharing, web sharing and ntfs security, is ok

------------------------
upload form
<html>
<body>

<form action="uploader.php" method="post" enctype="multipart/form-data">

<label for="file">Filename:<label>
<input type="file" name="file" id="file" >
<br >

<input type="submit" name="submit" value="Submit" >

</form>

</body>
</html>

------------------------
the uploader

<?php
if ($_FILES["file"]["error"] > 0)
  {
  echo
"Error: " . $_FILES["file"]["error"] . "<br />";
  }
else
  {
  echo
"Upload: " . $_FILES["file"]["name"] . "<br />";
  echo
"Type: " . $_FILES["file"]["type"] . "<br />";
  echo
"Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
  echo
"Stored in: " . $_FILES["file"]["tmp_name"];
  echo
"<br>";
  }

if (
file_exists("/php/upload/" . $_FILES["file"]["name"]))
      {
      echo
$_FILES["file"]["name"] . " already exists. ";
      }
    else
      {
     
move_uploaded_file($_FILES["file"]["tmp_name"],
     
"upload/" . $_FILES["file"]["name"]);
      echo
"Stored in: " . "upload/" . $_FILES["file"]["name"];
      }

?>
svenr at selfhtml dot org
23-Apr-2007 03:13
Clarification on the MAX_FILE_SIZE hidden form field:

PHP has the somewhat strange feature of checking multiple "maximum file sizes".

The two widely known limits are the php.ini settings "post_max_size" and "upload_max_size", which in combination impose a hard limit on the maximum amount of data that can be received.

In addition to this PHP somehow got implemented a soft limit feature. It checks the existance of a form field names "max_file_size" (upper case is also OK), which should contain an integer with the maximum number of bytes allowed. If the uploaded file is bigger than the integer in this field, PHP disallows this upload and presents an error code in the $_FILES-Array.

The PHP documentation also makes (or made - see bug #40387 - http://bugs.php.net/bug.php?id=40387) vague references to "allows browsers to check the file size before uploading". This, however, is not true and has never been. Up til today there has never been a RFC proposing the usage of such named form field, nor has there been a browser actually checking its existance or content, or preventing anything. The PHP documentation implies that a browser may alert the user that his upload is too big - this is simply wrong.

Please note that using this PHP feature is not a good idea. A form field can easily be changed by the client. If you have to check the size of a file, do it conventionally within your script, using a script-defined integer, not an arbitrary number you got from the HTTP client (which always must be mistrusted from a security standpoint).
v3 (&) sonic-world.ru
09-Mar-2007 02:29
As said before if POST size exceeds server limit then $_POST and $_FILES arrays become empty. You can track this using $_SERVER['CONTENT_LENGTH'].
For example:

<?php
$POST_MAX_SIZE
= ini_get('post_max_size');
$mul = substr($POST_MAX_SIZE, -1);
$mul = ($mul == 'M' ? 1048576 : ($mul == 'K' ? 1024 : ($mul == 'G' ? 1073741824 : 1)));
if (
$_SERVER['CONTENT_LENGTH'] > $mul*(int)$POST_MAX_SIZE && $POST_MAX_SIZE) $error = true;
?>
Buzer at buzer dot net
22-Feb-2007 12:18
Fairly easy way to generate MAX_FILE_SIZE:
<?php
$maxsize
= ini_get('upload_max_filesize');
if (!
is_numeric($maxsize)) {
    if (
strpos($maxsize, 'M') !== false)
       
$maxsize = intval($maxsize)*1024*1024;
    elseif (
strpos($maxsize, 'K') !== false)
       
$maxsize = intval($maxsize)*1024;
    elseif (
strpos($maxsize, 'G') !== false)
       
$maxsize = intval($maxsize)*1024*1024*1024;
}
print
'<input type="hidden" name="MAX_FILE_SIZE" value="'.$maxsize.'" />';
?>
jkuckartz1984 at hotmail dot com
31-Dec-2006 10:01
When uploading on a windows system and working with different partitions and different drive letters, uploading might not work correctly with the shown example.

The workaround is include the current operating directory in the target dir, as follows:

<?php
//you can delete the 'echo' commands and the '$temploc='-line
$currentdir=getcwd();
$target_path = $currentdir . "/2nddir/" . basename($_FILES['uploadedfile']['name']);
echo
"Target: $target_path<br>";
$temploc=$_FILES['uploadedfile']['tmp_name'];
echo
"Temploc: $temploc<br>";
if (
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    echo
"The file "basename( $_FILES['uploadedfile']['name']). " has been uploaded<br><br>";
} else {
    echo
"There was an error uploading the file, please try again!<br><br>";
}
?>

If the $currentdir is omitted and not used in $target_path:
Target: /2nddir/file.ext
Temploc: /ms4w/tmp/\php12C.tmp

Warning: move_uploaded_file(/ms4w/tmp/\php12C.tmp) [function.move-uploaded-file]: failed to open stream: No such file or directory in D:\Public\www\dir\test.php

Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move '/ms4w/tmp/\php12C.tmp' to '/2nddir/file.ext' in D:\Public\www\dir\test.php
There was an error uploading the file, please try again!

If it's written as the code shown above, it works perfectly:
Target: D:\Public\www\dir/2nddir/file.ext
Temploc: /ms4w/tmp/\php12C.tmp
The file file.ext has been uploaded

My initial thought the "\" in front of the temporary file was causing the problem. But don't bother about the "\", it does no harm!
jazfresh at hotmail.com
05-Dec-2006 11:46
Sample code for the upload progress extension below.
<?php
// upload_progress.php
// When the form is submitted, call this:
// window.open('/upload_progress.php?id=' + upload_identifier, 'Upload_Meter','width=370,height=115,status=no', true);
// Where 'upload_identifier' is the value of the hidden element UPLOAD_IDENTIFIER.

$id = $_GET['id'];
$body = false; // HTML body to display.
$onload = false; // Javascript to run when the page loads.
$refresh = false; // Number of seconds to wait before refreshing the page. false/0 means don't refresh.
$info = false; // Table of information to display
$url = htmlentities($_SERVER['PHP_SELF']).'?id='.$id.'&e=1'; // URL to redirect to.
$ul_info = uploadprogress_get_info($id);
if(!
$ul_info) {
   if(isset(
$_GET['e'])) {
       
$onload = 'window.close()';
       
$body = "Invalid upload meter ID!";
   } else {
       
$refresh = 2;   // Wait 2 seconds, give the server time to create the progress file.
       
$body = "Waiting for upload to begin.";
   }
} else {
    if(
$ul_info['bytes_total'] > 1 && $ul_info['bytes_uploaded'] >= $ul_info['bytes_total'] && $ul_info['est_sec'] == 0) {
       
$onload = 'window.close()';
       
$body = 'Upload complete.'; // They won't see this if the javascript runs, but just in case they've disabled it.
   
} else {
       
$body = "Uploading, please wait.";
       
$refresh = 1;
       
$percent_complete = $ul_info['bytes_uploaded'] * 100 / $ul_info['bytes_total'];
       
$kb_per_sec = $ul_info['speed_last'] / 1000;
       
$info = array(
           
'meter' => round($percent_complete, 2),
           
'width' => round($percent_complete),
           
'eta' => sprintf("%02d:%02d", $ul_info['est_sec'] / 60, $ul_info['est_sec'] % 60),
           
'speed' => round($kb_per_sec, ($ul_info['speed_last'] < 10000) ? 2 : 0),
           
'upl' => nice_value($ul_info['bytes_uploaded']),
           
'total' => nice_value($ul_info['bytes_total']),
            );
    }
}
// The HTML meter display should follow here.
?>
jazfresh at hotmail.com
05-Dec-2006 11:45
Now that PHP 5.2 supports a hook that can be used to handle upload progress, you can use a PECL extension (uploadprogress) to display an upload progress meter. Since documentation for this PECL extension is a bit thin on the ground, here are the basics:

1) Run "pecl install uploadprogress", and add "extension=uploadprogress.so" in your php.ini file.
2) Tell the extension where to temporarily store information about each upload. By default, this is in "/tmp/upt_%s.txt" (where %s is replaced with the UPLOAD_IDENTIFIER, see below). You can change it with the following config line:
uploadprogress.file.filename_template = /path/to/some_name_%s.txt
It must have a single '%s' in it, or it will fail!
3) Add a hidden element at the very beginning (this is important) of your upload form, called UPLOAD_IDENTIFIER. The value of this should be match the expression "^[A-Za-z0-9_.-=]{1,64}$" and be unique for every upload.
4) When the form is submitted, pop open a window to display the progress information and continue submitting the form. This window should refresh itself every few seconds, calling a PHP script that will retrieve the progress information and generate a display meter.

This script calls the function uploadprogress_get_info($id), where $id is the UPLOAD_IDENTIFIER value. This will return false if there is no progress information, or an array of values about that upload. The array contains:

time_start - The time that the upload began (same format as time()).
time_last - The time that the progress info was last updated.
speed_average - Average speed. (bytes / second)
speed_last - Last measured speed. (bytes / second)
bytes_uploaded - Number of bytes uploaded so far.
bytes_total - The value of the Content-Length header sent by the browser.
files_uploaded - Number of files uploaded so far.
est_sec - Estimated number of seconds remaining.

The speed_average is measured based on the number of bytes uploaded since the upload began, whereas the speed_last is based on the number of bytes uploaded since the progress information was last updated. The progress information is updated whenever PHP reads in some more data from the client, so speed_last may not be very accurate.

Note 1) The bytes_total figure is NOT a reflection of the file size, but of the POST's size, so don't expect them to match.

Note 2) This module really only detects how much data the POST form has sent, and keeps a running count of how many POST variables of type 'file' that it encounters along the way.  It has no way of knowing how many files are in the POST, so it is not possible to have a progress bar for each file, just one for all files (and the ability to display how many files have been uploaded so far).
nebileyimya at gmail dot com
29-Nov-2006 01:29
i never work all above code
and i try this work fine

 $file_name = $_FILES['file']['tmp_name'];
                    $localfile = file_get_contents($file_name);
                    $handle = fopen($_FILES['file']['name'],"w");
                    if(fwrite($handle,$localfile)>-1)
                    {
                    echo "done";
                    }
                    else
                    {
                    echo "error";
                    }
frustrated dot user at fake dot com
28-Nov-2006 09:11
Before you even bother doing anything, verify the filesystem your permanent upload directory will reside on. Use NTFS before you even start! (Assuming you're on Windows.)

Unfortunately, because I've been preparing to switch to Linux on this machine, I thought it would be a *great* idea to use FAT32 so I could access my websites from both Windows and Linux (this is not a production box, but where I am creating a CMS).

This was a *bad* idea...since the filesystem is not NTFS, now the only permissions I can set are *share* permissions.

I *guess* that *share* permissions are not used through the webserver, because even though the user Apache runs as is one of the users given permissions "Read" and "Modify" share permissions, the file cannot be permanently saved via neither move_uploaded_file() nor copy().

I verified this by using conditionals with !is_readable() and !is_writable() to echo specific messages.

So, now I have to back up everything I've done, reformat that partition as NTFS, copy everything over again, and set all the permissions, including on databases that I am using with other pages. *(sigh)*
08-Nov-2006 04:24
Upload Progress Meter extension for PHP 5.2

for who was wondering how to do this here is a tip: take a look at
http://blog.bitflux.ch/archive/2006/09/28/
upload-progress-meter-extension-for-php-5-2.html

this guy did it for us

Thanks Christian!
rburdick at wAppearances dot com
23-Oct-2006 10:44
I have an application with a file upload page.  I notice that if I enter garbage in the filename text box associated with the <input type="file"> element associated with my multipart upload form, the form does not get submitted when the submit button is clicked.  There is no custom form validation JavaScript code associated with the form.  Can anyone tell me if multipart forms do any kind of default validation of their own?

Robert
jedi_aka at yahoo dot com
18-Oct-2006 12:12
For those of you trying to make the upload work with IIS on windows XP/2000/XP Media and alike here is a quick todo.

1) Once you have created subdirectories "uploads/"  in the same directory wher you code is running use the code from oportocala above and to make absolutely sure sure that the file you are trying to right is written under that folder. ( I recomend printing it using echo $uploadfile; )

2) In windows explorer browse to the upload directory created above and share it. To do that execute the following substeps.
     a) Right click the folder click "sharing and security..."
     b) Check 'Share this folder on the network'
     c) Check 'Allow network users to change my files' ( THIS STEP IS VERY IMPORTANT )
     d) click 'ok' or 'apply'

3) you can then go in the IIS to set read and write permissions for it. To do that execute the followin substeps.
     a) Open IIS (Start/Controp Panel (classic View)/ Admistrative tools/Internet Information Service
     b) Browse to your folder (the one we created above)
     c) right click and select properties.
     d) in the Directory tab, make sure, READ, WRITE, AND DIRECTORY BROWSING are checked.
     e) For the security freaks out there, You should also make sure that 'execute permissions:' are set to Script only or lower (DO NOT SET IT TO 'script and executable)'( that is because someone could upload a script to your directory and run it. And, boy, you do not want that to happen).

there U go.

Send me feed back it if worked for you or not so that I can update the todo.

jedi_aka@yahoo.com

PS: BIG thanks to oportocala
tom dot blom at helsinki dot fi
04-Sep-2006 06:02
I have been upgrading a web server. The current configuration is IIS 6.0 + PHP 5.2 build 3790 with SSL support.

File uploads failed with a blank screen if the file size exceeded ca. 49 Kb. I tried modifying different timeout parameters (PHP and IIS) and the POST_MAX_SIZE and UPLOAD_MAX_FILESIZE directives. Modifications had no effect.

After turning off SSL in IIS uploads were successful. Some experimenting showed  that the "Accept client certificates" -setting was causing the problem. Now I am running IIS with SSL and "Ignore client certificates" -setting. Even large files can now be uploaded.

I didn't found anything about this feature on the web.
chris[underscore]lewis[AT]bellsouth.net
17-Aug-2006 08:16
Remember that upload sizes are also affected by the setting <i>post_max_size</i>. If the file size, or more accurately the post size (file size + header data) is exceeded, PHP seems to just die. From what I've found so far, there doesn't even seem to be any entries to the apache log regarding the failure! So basically if you exceed the post size, a user will have no idea that anything failed. If anyone can expand on this, please do so!
my dot ma-ma at googlesucks dot com
14-Jul-2006 12:41
$userfile_name
is disallowed when register_globals is deactivated
ivan DOT cukic AT gmail DOT com
20-May-2006 05:47
There was a post earlier about not using the $_FILES['userfile']['type'] for verification and that a malicious PHP file could be hidden under the image/gif mime type.

That is correct, but it is not enough just to use getImageSize() or exif_imagetype() because php code can be hidden in the comment part of the picture.

The only way you can be sure it will not be executed is to make sure that the extension is not recognized by the server as a php script.

If you want a proof of concept, open The GIMP and create a 10x10px blank GIF image. When saving, just enter <? phpinfo() ?> as GIF comment. Rename the saved file from something.gif into the something.php and ask the server for it.

(And make sure that you NEVER call include() with a file that was uploaded)
david at cygnet dot be
12-May-2006 05:14
If you are experiencing problems posting files from Internet Explorer to a PHP script over an SSL connection, for instance "Page can not be displayed" or empty $_FILES and $_POST arrays (described by jason 10-Jan-2006 02:08), then check out this microsoft knowledgebase article:

http://support.microsoft.com/?kbid=889334

This knowledgebase article explains how since service pack 2 there may be problems posting from IE over SSL. It is worth checking whether your problem is IE specific since this is definitely not a PHP problem!
07-Apr-2006 12:28
If you're having a problem with filenames because of magic quotes, use stripslashes() to...strip slashes.
kweechang at yahoo dot com
07-Apr-2006 12:34
I have the same problem with filename contains single quote. Currently, I am using web-hosting services, hence I am not able to switch magic_quotes_gpc on/off.

After some study, I have discovered that the cause of the problem is in function basename();

For example:
$windows_filename = "C:\tmpdir\ling's document.doc"

with magic_quotes_gpc on
it becames
$windows_filename = "C:\\tmpdir\\ling\'s document.doc"

if you do a

  echo basename($windows_filename)

the result will be
   "s document.doc"

which is not correct, but this is exactly what we get from $_FILES['userfile']['name'];

To work around with this problem, the following solution might work.

Step 1:
a) Include a hidden field "userfilename" in your form.
b) add a javascript to the "file" input. To objective is to dupilcate the full filename and post it to the host.

<form name="imgform" method="post" action="upload.php" enctype="multipart/form-data">
   <input type="hidden" name="userfilename" id="userfilename">
   <input type="file" name="userfile" id="userfile" size="64" maxlength="256" onChange="javascript:top.document.imgform.userfilename.value= top.imgform.userfile.value">
</form>

Step 2:
a) extract the filename from the "userfilename"

        $fileName = $_FILES['userfile']['name'];
        $tmpName  = $_FILES['userfile']['tmp_name'];
        $fileSize = $_FILES['userfile']['size'];
        $fileType = $_FILES['userfile']['type'];
        
        $fp = fopen($tmpName, 'r');
        $content = fread($fp, $fileSize);
        $content = addslashes($content);
        fclose($fp);
        
        if(!get_magic_quotes_gpc())
        {
            $fileName = addslashes($fileName);
        } else {
    $fileName = addslashes(basename(stripslashes($_POST['userfilename'])));
        }
chaz_meister_rock at yahoo dot com
09-Mar-2006 10:09
As mentioned in this thread by mariodivece at bytedive dot com on 24-Aug-2005 12:33:

"when using base64_encode to store binary data in a database, you are increasing the size of the data by 1.33 times."

so, if you are receiving the dreaded "MySQL Server has gone away" error when uploading BLOB data encoded w/base64, remember that your MySQL "max_allowed_packet" configuration setting (default 1MB) needs to by 1.33 times the size of your PHP "upload_max_filesize" setting.
brett dot r dot brown at gmail dot com
12-Jan-2006 03:01
In regards to geert dot php at myrosoft dot com about having the filenames cut off if single quotes are present in the filename, I had this same problem.  The solution to this, is to set magic_quotes_gpc to off.
When magic_quotes_gpc is on, whenever a single quote is present in any _post data, a \ is inserted before any single quotes as an escape character.  This comes in handy if you're storing the post data into mySQL, but causes problems, as you've had, when receiving an upload.
jason
09-Jan-2006 05:08
Regarding empty $_FILES and $_POST arrays when uploading files larger than post_max_size:

Tucked away in http://us3.php.net/manual/en/ini.core.php#ini.post-max-size is this nugget:

"If the size of post data is greater than post_max_size, the $_POST and $_FILES superglobals are empty. This can be tracked in various ways, e.g. by passing the $_GET variable to the script processing the data, i.e. <form action="edit.php?processed=1">, and then checking if $_GET['processed'] is set."

This may seem like a bug. You'd expect something like UPLOAD_ERR_FORM_SIZE to be set. But you just two empty superglobals.

I've seen it submitted to bugs.php.net twice and it's been marked as bogus both times.
Marcus
04-Jan-2006 07:11
Many ppl uses a java applet for uploading files instead of a forms post. This way you can get a progress bar etc.

If you for some reason cannot upload very large files you can use the java applet to upload it in chunks. I made a small change to the free JUpload applet hosted at sourceforge to do this.

If you in the url you're posting to add the argument
 juchunksize=integervalue
the upload will be done as several posts where max-size of one part is integervalue. So you can keep track of where you are, two more parameters are added:
 jupart, which is 0..
 jufinal, which is 0 when there is more left or 1 if finished.

address to project:
http://sourceforge.net/projects/jupload

link to this JUpload version is here:
http://tinyurl.com/a2j7t
geert dot php at myrosoft dot com
23-Dec-2005 12:16
When file names do contain single quote parts of the filename are being lost.
eg.: uploading a filename
      startName 'middlepart' endName.txt
will be uploaded (and hence stored in the _Files ['userfile'] variable as
      endName.txt
skipping everything before the second single quote.
pete at NOSPAMpetesmithcomputers dot com
08-Dec-2005 05:03
I find I often have to handle photos in CMSs, so I wrote this class. It doubtless needs improvements, but it works pretty well.
<?php
class picture
{
        var
$save_dir;                     //where file will be saved
       
var $filename="spacer.gif";        //default file name initially
       
var $error_message="";             //string to be output if neccesary
       
var $width;                        //height of final image
       
var $height;                       //width of final image

       
function picture($save_directory, $file_array, $max_width, $max_height)
        {
               
$this->save_dir = $save_directory;               
               
$this->width =    $max_width;
               
$this->height =   $max_height;

               
//--change filename to time - make it unique
               
$temp_filename = $file_array['name'];
               
$ext = explode('.',$temp_filename);
               
$ext = $ext[count($ext)-1];
               
$temp_filename = time().".".$ext;

               
//--check that it's a jpeg or gif
               
if (preg_match('/^(gif|jpe?g)$/',$ext)) {
                       
// resize in proportion
                       
list($width_orig, $height_orig) = getimagesize($file_array['tmp_name']);
                        if (
$this->width && ($width_orig < $height_orig)) {
                               
$this->width = ($this->height / $height_orig) * $width_orig;
                        } else {
                               
$this->height = ($this->width / $width_orig) * $height_orig;
                        }

                       
$image_p = imagecreatetruecolor($this->width, $this->height);                       

                       
//handle gifs and jpegs separately
                       
if($ext=='gif'){
                           
$image = imagecreatefromgif($file_array['tmp_name']);                           
                           
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $this->width, $this->height, $width_orig, $height_orig);
                           
imagegif($image_p, $this->save_dir.$temp_filename, 80);
                        }
                        else
                        {
                           
$image = imagecreatefromjpeg($file_array['tmp_name']);                            
                           
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $this->width, $this->height, $width_orig, $height_orig);                           
                           
imagejpeg($image_p, $this->save_dir.$temp_filename, 80);
                        }

                       
imagedestroy($image_p);
                       
imagedestroy($image);

                       
$this->filename=$temp_filename;

                }else{
                       
$this->error_message.="<br> file is not a jpeg or gif picture <br>";
                }
        }
}
?>
djot at hotmail dot com
27-Nov-2005 02:02
-
Be carefull with setting max_file_size via
ini_get('upload_max_filesize');

ini_get might return values like "2M" which will result in non working uploads.

This was the "no no" in my case:

$form = '<input type="hidden" name="MAX_FILE_SIZE" value=".ini_get('upload_max_filesize')." />';

Files were uploaded to the server, but than there was not any upload information, not even an error message. $_FILES was completly empty.

djot
-
info at giel berkers dot com
09-Nov-2005 04:03
I had problems when uploading files using Internet Explorer and Firefox. I checked for extension and mime-type to make sure it was a jpeg-file my users uploaded. Firefox did it well, only Internet Explorer failed to accept the file saying it wasn't the correct mime-type. After some testing, I discovered that Firefox reads the mime-type of a Jpeg-image as:

image/jpeg

While Internet Explorer reads it as:

image/pjpeg

I hope this helps somebody to avoid an evening debugging. To contribute to php.net, I enclosed my secure upload script for Jpeg files:

<?php
   
 
function storefile($var, $location, $filename=NULL, $maxfilesize=NULL) {
   
$ok = false;

   
// Check file
   
$mime = $_FILES[$var]["type"];
    if(
$mime=="image/jpeg" || $mime=="image/pjpeg") {
     
// Mime type is correct
      // Check extension
     
$name  = $_FILES[$var]["name"];
     
$array = explode(".", $name);
     
$nr    = count($array);
     
$ext   = $array[$nr-1];
      if(
$ext=="jpg" || $ext=="jpeg") {
       
$ok = true;
      }
    }
   
    if(isset(
$maxfilesize)) {
      if(
$_FILES[$var]["size"] > $maxfilesize) {
       
$ok = false;
      }
    }
   
    if(
$ok==true) {
     
$tempname = $_FILES[$var]['tmp_name'];
      if(isset(
$filename)) {
       
$uploadpath = $location.$filename;
      } else {
       
$uploadpath = $location.$_FILES[$var]['name'];
      }
      if(
is_uploaded_file($_FILES[$var]['tmp_name'])) { 
       while(
move_uploaded_file($tempname, $uploadpath)) {
         
// Wait for the script to finish its upload   
       
}
      }
      return
true;
    } else {
      return
false;
    }
  }

?>

You can use this script as follow:

<?

if(isset($_FILES['name'])) {
  if(storefile("name", $_SERVER['DOCUMENT_ROOT']."test/img")) {
    echo("Upload succeeded!");
  } else {
    echo("Upload failed...");
  }
}

?>

The last 2 parameters 'filename' and 'maxfilesize' are optional. Offcourse, you can change this script with other mime types and extensions to fit your needs.
ohdotoh at randomnoisebursts dot com
10-Oct-2005 12:33
my quick and simple don't overwrite files that exist solution:

if (file_exists($sysfolder . '/' . $filename)) {
// append a digit to the beginning of the name
  $tmpVar = 1;
  while(file_exists($sysfolder . '/' . $tmpVar . '-' . $filename)) {
// and keep increasing it until we have a unique name
    $tmpVar++;
    }
  $filename= $tmpVar . '-' . $filename;
  }
ded at in dot ua
04-Oct-2005 02:03
Generally, if you use
CharsetDisable on
or
CharsetSourceEnc off
in (russian) apache config file, and if your script which receives upload still have some html, use <meta http-equiv ...> tags so browser can correctly display the pages.
andrea at 3site dot it
21-Sep-2005 08:05
Hello, here is an experimental PHP / AJAX method to monitoring upload status.
http://www.devpro.it/upload_progress/

Thank you, PHP !!!
NO_lewis_SPAM at NOSPAM dot delta-hf dot co dot uk
03-Sep-2005 09:27
I have been having issues with putting data in to an MSSQL database from an uploaded file. Trying to INSERT a file in excess of 25MB caused "Insufficient memory" errors from the SQL server

I decided to chunk the data into the database rather than trying to spurt it all in at once. The memory management is much better and from Submit to in the DB takes about 1 second per MB. The machine has dual Pentium 3 933MHz and 2GB RAM.

First things first I had to write a stored procedure. I saw no point in attempting to return a TEXTPTR(), which is required for the UPDATETEXT function to work, back to PHP so I didn't even bother. This is my very first stored procedure since this is really the first time I've developed solely for MSSQL. The important thing is that it's functional.

Here's the code I used for my stored procedure. After writing this I need to execute it in a loop to get all the data in, in the correct order. I leave that bit to PHP of course. Please don't tell me I could have just written it all in the stored procedure using another language, this is PHP and MSSQL we're talking about. :)

The zipfile column data type is TEXT, I tried IMAGE but it was problematic dealing with HEX data.

///////////// SP//////////////////////
CREATE PROCEDURE dbo.dds_writeBlob @dataChunk AS TEXT, @refCode AS VARCHAR(50), @offSet AS INT

AS

DECLARE    @dataPtr AS BINARY(16)

SELECT    @dataPtr=TEXTPTR(zipfile)
FROM    [dbo].[file] (UPDLOCK)
WHERE    [dbo].[file].ref = @refCode

UPDATETEXT    [dbo].[file].zipfile @dataPtr @offSet 0 @dataChunk
GO
//////////////////END SP/////////////////

Then of course comes the PHP code to do the chunking. Firstly I have to convert the binary data to a type that can be accepted by TEXT data type. base64_encode() comes in handy for this purpose but of course I need it in chunks so I used chunk_split() and split it in to chunks of 256000 bytes by declaring the optional [chunklen]. I then explode() it in to a numerically indexed array using the newlines ("\r\n") that are inserted every [chunklen] by chunk_split. I can then loop through with a for(), passing the data chunks, in order, one at a time to the stored procedure. Here's the code:

<?
$data = chunk_split(base64_encode(fread(fopen($file, "rb"), filesize($file))), 256000);
$arrData = explode("\r\n", $data);
unset($data); // Clear memory space
$num = count($arrData);
$offset = 0;

for ($i=0;$i<$num;$i++) {
    $buffer = $arrData[$i];
    $query = "EXEC [dds_writeBlob] '".$buffer."', '$reference', $offset";
    @mssql_query($query) or die(mssql_get_last_message());
    $offset = ($offset + strlen($buffer));
}
?>
 
Of course we then need to extract the data from the database. This, thankfully, is a lot easier! Simply base64_decode() the data before outputting to a browser.
<?
$query = "SELECT zipfile, job_code FROM [file] WHERE ref = '$ref'";
@$result = mssql_query($query) or die('File Download: Failed to get file from the database.');
$file = mssql_fetch_assoc($result);
header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="job-'.trim($file['job_code']).'.zip"');
echo base64_decode($file['zipfile']);
?>

The benefit of storing in base64_encoded format is the simplicity with which you can now send mime emails with the data attached as an alternative to having people download it. A simple chunk_split() on the SELECTed data will have it in the right format for mime mails.

The draw back is the extra size required! Expect the base64_encoded data to be 1.33 times the size of the original data!
Dave Koopman
24-Aug-2005 07:22
Upload progress bar by patching PHP source code.  Uses file or MySQL table to log progress.  MySQL is useful in load balanced situations. 

http://www.modphp.org/viewtopic.php?t=324
mariodivece at bytedive dot com
24-Aug-2005 11:33
Just wanted to point out a detail that might be of interest to some:

when using base64_encode to store binary data in a database, you are increasing the size of the data by 1.33 times. There is a nicer way of storing the data directly. Try the following:

<?php $data = mysql_real_escape_string($data); ?>

This will leave the data untouched and formatted in the correct way and ready to be inserted right into a MySQL statement without wasting space.

By the way, I'd like to thank therebechips for his excellent advice on data chunks.
warwickbarnes at yahoo dot co dot uk
18-Aug-2005 04:58
You may come across the following problem using PHP on Microsoft IIS: getting permission denied errors from the move_uploaded_file function even when all the folder permissions seem correct. I had to set the following to get it to work:

1. Write permissions on the the folder through the IIS management console.
2. Write permissions to IUSR_'server' in the folder's security settings.
3. Write permissions to "Domain Users" in the folder's security settings.

The third setting was required because my application itself lives in a secure folder - using authentication (either Basic or Windows Integrated) to identify the users. When the uploads happen IIS seems to be checking that these users have write access to the folder, not just whether the web server (IUSR_'server') has access.

Also, remember to set "Execute Permissions" to "None" in the IIS management console, so that people can't upload a script file and then run it. (Other checks of the uploaded file are recommended as well but 'Execute None' is a good start.)
myko AT blue needle DOT com
16-Aug-2005 09:13
Just a quick note that there's an issue with Apache, the MAX_FILE_SIZE hidden form field, and zlib.output_compression = On.  Seems that the browser continues to post up the entire file, even though PHP throws the MAX_FILE_SIZE error properly.  Turning zlib compression to OFF seems to solve the issue.  Don't have time to dig in and see who's at fault, but wanted to save others the hassle of banging their head on this one.
muoihv at 1yt dot net
04-Aug-2005 01:47
// Split file Submit and HTML post

<?
$num_of_uploads=3;
$file_types_array=array("JPG");
$max_file_size=1048576;
$upload_dir="D:\AppServ\www";

function uploaderFILES($num_of_uploads=1, $file_types_array=array("JPG"), $max_file_size=1048576, $upload_dir=""){
  if(!is_numeric($max_file_size)){
   $max_file_size = 1048576;
  }
  foreach($_FILES["file"]["error"] as $key => $value)
  {
     if($_FILES["file"]["name"][$key]!="")
     {
       if($value==UPLOAD_ERR_OK)
       {
         $origfilename = $_FILES["file"]["name"][$key];
         $filename = explode(".", $_FILES["file"]["name"][$key]);
         $filenameext = $filename[count($filename)-1];
         unset($filename[count($filename)-1]);
         $filename = implode(".", $filename);
         $filename = substr($filename, 0, 15).".".$filenameext;
         $file_ext_allow = FALSE;
         for($x=0;$x<count($file_types_array);$x++){
           if($filenameext==$file_types_array[$x])
           {
             $file_ext_allow = TRUE;
           }
         } // for
         if($file_ext_allow){
           if($_FILES["file"]["size"][$key]<$max_file_size){
             if(move_uploaded_file($_FILES["file"]["tmp_name"][$key], $upload_dir.$filename)){
               echo("File uploaded successfully. - <a href='".$upload_dir.$filename."' target='_blank'>".$filename."</a><br />");
             }
             else { echo('<font color="#FF0000">'.$origfilename."</font> was not successfully uploaded - khong the upload duoc <br />");}
           }
           else  { echo('<font color="#FF0000">'.$origfilename."</font> was too big, not uploaded - Kich thuoc file qua' lon <br />"); }
         } // if
         else{ echo('<font color="#FF0000">'.$origfilename." </font>had an invalid file extension, not uploaded - File nay khong ton tai <br />");   }
       }
       else{ echo('<font color="#FF0000">'.$origfilename." </font>was not successfully uploaded - khong the upload duoc <br />");  } // else
     }
  }
} // funtion

/////////////////////////////////////////
?>
  <form action='<?=$PHP_SELF;?>' method='post' enctype='multipart/form-data'>Upload files:<br /><input type='hidden' name='submitted' value='TRUE' id='<?=time();?>' >
  <input type='hidden' name='MAX_FILE_SIZE' value='<?=$max_file_size;?>' >
<?   for($x=0;$x<$num_of_uploads;$x++){
     $form .= "<input type='file' name='file[]'><br />";
   }
   $form .= "<input type='submit' value='Upload'><br />
   <font color='red'>*</font>Maximum file length (minus extension) is 15 characters. Anything over that will be cut to only 15 characters. Valid file type(s): ";
   for($x=0;$x<count($file_types_array);$x++){
     if($x<count($file_types_array)-1){
       $form .= $file_types_array[$x].", ";
     }else{
       $form .= $file_types_array[$x].".";
     }
   }
    echo($form);
?>   
  </form>
 

//////////////////////////////////////
<?
if(isset($_POST["submitted"])){
    uploaderFILES($num_of_uploads, $file_types_array, $max_file_size, $upload_dir);
}
?>
dan at DLC2 dot com
01-Aug-2005 01:19
Are you struggling to implement these code samples for "file upload" or "multiple file upload"? Are you still scratching your head why they don't work??

I tried everything, until I realized that my version of PHP was too old! Look at these tidbits (collected from pages at PHP.NET for your enjoyment):

Requires PHP v4.1 - The $_FILES array

Requires PHP v4.2 - The "error" sub-array - example: $_FILES["userfile"]["error"]

Requires PHP v4.3 - The constants for "error" sub-array - example: UPLOAD_ERR_OK (value 0)

So, if you have PHP v4.0.X or earlier, use the $HTTP_POST_FILES variable and just do without the error sub-array and it
Новости
11 июля 2007
Сайт запущен
© 2007 info@grandviewstudio.com
щенки алабая ; чем склеить видеофайлы Z058440144362 Z348613067571