Сделал с божьей помощью совсем простой скрипт загрузки файлов(фото) на сайт. Проблема - файл не записывается, так как нет пров у пользователя на каталог. Выяснил, что после выбора файла (владелец vlm) в форме, происходит запись в каталог /opt/lampp/temp/. И вот здесь файл получает нового хозяна - daemon. Новый пользователь - демон (моя ОС - Linix Manjaro), пытается записать файл в мой каталог, dir5, (хозяин также, как и везде - vlm) например, на который у него нет прав. Если я меняю права доступа, то есть каждый имеет право на запись в этот мой каталог, то происходит сохранение и все ОК. В этом случае владельцем этого файла (фотографии) остается демон. Предполагаю, что это связано с какими-то графическими функциями (собственно все упирается в move_uploaded_file), но не уверен и не понимаю, как это исправить. То есть все по-простому, пользователь vlm взял свой родной файл и загруззил его в свой католог. Прошу помощи, скрипт ниже. PHP: <?php declare ( strict_types=1 ); ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Upload Photo</title> </head> <body> <form action="upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="image"> <input type="submit" name="upload" value="Upload"> </form> </body> </html> <?php if (isset($_POST['upload'])) { if (empty($_FILES['image']['name'])) { echo "Выбери файл, идиот."; } if ($_FILES['image']['error'] != UPLOAD_ERR_OK) { echo "Error !!!."; } $allowed_extensions = ['jpg', 'jpeg', 'JPG','JPEG', 'png']; $file_extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION); if (!in_array($file_extension, $allowed_extensions)) { echo "Тип неверен."; } $destination_path = 'gallery/user5/' . basename($_FILES['image']['name']); echo 'DestPath = '.$destination_path; echo '<br>FILES-TMP = '.$_FILES['image']['tmp_name']; if (!move_uploaded_file($_FILES['image']['tmp_name'], $destination_path)) { echo "Ошибка записи."; } echo "Загрузка выполнена."; }
Дело было не в бобине (с) .... Скрипт тут не при чем... тут нужно смотреть настройку вашего веб-сервера - под каким пользователем он выполняет php? И вообще какая версия у вас php? fpm?, После выбора файла в форме - никаких владельцев у него быть не может - пока файл физически не появится в вашей системе... смотрите какие права в временной этой директории... этот бред откуда вам в голову пришел? в скрипте никаких dir5 никаких графических функций в move_uploaded_file - нет, работать может с любыми файлами.. не только с графическими и вообще слишком много напридумывали.... 99% дело в правах на папку или в неверной настройке прав в целом в системе... у gallery/user5 должны быть права 755.... если не поможет - значит в системе что то не то - можно выставить 777
Добрый день! Согласен, ADSoft. Советую Вам добавить в скрипт file-preview PHP: <?php declare ( strict_types=1 ); ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <img src="#" alt="Preview Uploaded Image" id="file-preview"> <title>Upload Photo</title> <style> #file-preview{display: none} </style> </head> <body> <form action="" method="post" enctype="multipart/form-data"> <input type="file" name="image" id='fileToUpload'> <img src="#" alt="Preview Uploaded Image" id="file-preview"> <input type="submit" name="upload" value="Upload"> </form> </body> <script> const input = document.getElementById('fileToUpload'); const previewPhoto = () => { const file = input.files; const preview = document.getElementById('file-preview'); if (file) { const fileReader = new FileReader(); const preview = document.getElementById('file-preview'); fileReader.onload = function (event) { preview.setAttribute('src', event.target.result); preview.style.display="block"; } fileReader.readAsDataURL(file[0]); } else preview.style.display="none"; } input.addEventListener("change", previewPhoto); </script> </html> <?php if (isset($_POST['upload'])) { if (empty($_FILES['image']['name'])) { echo "Выбери файл, идиот."; } if ($_FILES['image']['error'] != UPLOAD_ERR_OK) { echo "Error !!!."; } $allowed_extensions = ['jpg', 'jpeg', 'JPG','JPEG', 'png']; $file_extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION); echo "33:".$_FILES['image']['name']." $file_extension"; if (!in_array($file_extension, $allowed_extensions)) { echo "Тип неверен."; } $destination_path = 'gallery/user5/' . basename($_FILES['image']['name']); echo '<br>FILES-TMP = '.$_FILES['image']['tmp_name']; if (!move_uploaded_file($_FILES['image']['tmp_name'], $destination_path)) { echo "Ошибка записи."; } echo "Загрузка выполнена."; } Удачи!
Хм.... 1. СПАСИБО. 2. "в скрипте никаких dir5" - да, неправильно скопировал, потом изменил на user5". PHP: $destination_path = 'gallery/user5/' . basename($_FILES['image']['name']); 3. Версия PHP - 8.1 4. Сообщение - DestPath = /gallery/user5/SAM_0145.JPG FILES-TMP = /opt/lampp/temp/phpHsRaU7 Warning: move_uploaded_file(/gallery/dir5/SAM_0145.JPG): Failed to open stream: Datei oder Verzeichnis nicht gefunden in /opt/lampp/htdocs/foto/upload.php on line 52 Это line 52 - if (!move_uploaded_file($_FILES['image']['tmp_name'], $destination_path)). 5. То есть по умолчанию система запихивает сначала в /opt/lampp/temp/. У меня стоит XAMPP, соответственно Apache. А если бы не было установлено, то что использовалоь бы и как это определяется? Этот Каталог принадлежит root. Теперь я меняю доступ для user5 на 757. Вот результат - DestPath = gallery/user5/SAM_0194.JPG FILES-TMP = /opt/lampp/temp/phpyUPWtT File uploaded successfully. Но теперь у файла SAM_0194.JPG влоделец новый, а именно - daemon. Именно это НЕ пониманию вооще.... 6. С JS завтра надеюсь попробовать. Спасибо еще раз.
Ну, выкрутиться можно, видимо, chown или права доступа менять... Но это как-то криво и так нормальные люди думаю не делают. И второе - хочется понять где и как собака зарыта ( помимо той, которая в голове у меня)
757 не совсем кошерные права.... папка gallery/user5 создается динамически, из скрипта? или в системе на момент загрузки существует с необходимыми правами? если создаете динамически - перед загрузкой файла - меняйте права .... Я обычно при создании папки делаю так PHP: mkdir($folder, 0755, true) и при успешной загрузке файла PHP: chmod($destination,0644); что как-бы нивелирует возможно неверную настройку веб-сервера
1. папка gallery/user5 создается динамически, из скрипта? Нет, заранее создана. 2. Но я так и не понимаю , не знаю ответ на вопросы - По умолчанию система запихивает сначала в /opt/lampp/temp/. У меня стоит XAMPP, соответственно Apache. А если бы не было установлено, то что использовалоь бы и как это определяется? Этот Каталог принадлежит root. Теперь я меняю доступ для user5 на 757. Вот результат - DestPath = gallery/user5/SAM_0194.JPG FILES-TMP = /opt/lampp/temp/phpyUPWtT File uploaded successfully. Но теперь у файла SAM_0194.JPG влоделец новый, а именно - daemon. С какой радости? Спасибо
Определяестя в php.ini https://www.php.net/manual/ru/ini.core.php#ini.upload-tmp-dir По всей видимости daemon - это пользователь от которого работает веб-сервер.
1. Если я правильно открыл- Внимание Эта опция УДАЛЕНА в PHP 7.2.0. 2. По всей видимости daemon - это пользователь от которого работает веб-сервер. Ну так и чего? Почему во всез других скиптах здесь и других проектов он в подполье, а именно здесь ворует файл?
Попробовал c JS, как Vladimir Kheifetz предложил. 1. Сообщение - DestPath = gallery/user2/20140927_144106.jpg FILES-TMP = /opt/lampp/temp/phpS2Kivt Warning: move_uploaded_file(gallery/user2/20140927_144106.jpg): Failed to open stream: Keine Berechtigung in /opt/lampp/htdocs/foto/upload.php on line 82. 2. Меняю права доступа для чужих сволочей. После этого сообщение - DestPath = gallery/user2/20140926_233229.jpg FILES-TMP = /opt/lampp/temp/phpEVOCjY File uploaded successfully. 3. Хозяин файла - daemon. То есть ничего не меняется, как и следовало ожидать, за исключеним того, что картинку (фото)) перед загрузкой выводит на экран. В общем в тумане нахожусь, как и раньше.
Добрый день! Давайте попробуем отвлечься от потусторонних сил и сделать нечто полезное. Предложим, что пользователи после логина могут загружать картинки в поддиректории user1, user2, user3… директории gallery, где 1,2,3… - userId Попробуем удалить как-то заранее созданные папки. Затем так изменим код: PHP: <?php declare ( strict_types=1 ); ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); $_SESSION["userId"]=5; //временно для отладки ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <img src="#" alt="Preview Uploaded Image" id="file-preview"> <title>Upload Photo</title> <style> #file-preview{display: none} </style> </head> <body> <form action="" method="post" enctype="multipart/form-data"> <input type="file" name="image" id='fileToUpload' accept = "image/png, image/jpeg" required> <img src="#" alt="Preview Uploaded Image" id="file-preview"> <input type="submit" name="upload" value="Upload"> </form> </body> <script> const input = document.getElementById('fileToUpload'); const previewPhoto = () => { const file = input.files; const preview = document.getElementById('file-preview'); if (file) { const fileReader = new FileReader(); const preview = document.getElementById('file-preview'); fileReader.onload = function (event) { preview.setAttribute('src', event.target.result); preview.style.display="block"; } fileReader.readAsDataURL(file[0]); } else preview.style.display="none"; } input.addEventListener("change", previewPhoto); </script> </html> <?php if (isset($_POST['upload'])) { if (empty($_FILES['image']['name'])) { echo "Выбери файл, идиот."; } if ($_FILES['image']['error'] != UPLOAD_ERR_OK) { echo "Error !!!."; } $allowed_extensions = ['jpg', 'jpeg', 'JPG','JPEG', 'png']; $file_extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION); if (!in_array($file_extension, $allowed_extensions)) { echo "Тип неверен."; } $userId = $_SESSION["userId"]; //присваивается после логина $destination_path = "gallery/user$userId/"; if(!is_dir($destination_path)) mkdir($destination_path); $destination_path .= basename($_FILES['image']['name']); if (!move_uploaded_file($_FILES['image']['tmp_name'], $destination_path)) { echo "Ошибка записи."; } echo "Загрузка выполнена."; } ?> Обратите внимание на небольшое изменение тэга file. Я добавил атрибут accept = "image/png, image/jpeg" это mime-тип файлов, которые разрешается загружать, а атрибут required определяет это поле как обязательное для заполнение В том случае если файл не выбран будет выдаваться сообщение и форма не будет отправляться. Удачи!
1.Danke. 2. " Давайте попробуем отвлечься от потусторонних сил и сделать нечто полезное." С этим на данный момент бытия проблема. 2.1 Силы сверху сильны и реальность изменяют. То есть - я все делаю на своем РС дома, Линух. При установке Линух кроме root был установлен только один user vlm. 2.2 Никаких "левых" проблем с правами доступа и пр. как при обычных действиях, так и при разработке сайтов (XAMPP, Netbeans, ..) не было. 2.3 Каталог (user5 и др.) уже созданы пользователем vlm, пока не врубаюсь, что изменится, если его делать динамически. 2.4 Есть еще notebook, тоже Линух. Попробовал там. Результат точно такой же!!! 2.5 Получил ответ от ИИ на вопрос - You are correct, the /opt/lampp directory is not a default directory in Linux and is only present if XAMPP or Apache is installed. This is because XAMPP is a pre-packaged development environment that includes Apache, MySQL, and PHP. When you install XAMPP, it creates the /opt/lampp directory to store its configuration and files. The move_uploaded_file function is part of the PHP standard library and is not specific to XAMPP or Apache. It will attempt to write the temporary file to the system's temporary directory, which is typically specified in the TMPDIR environment variable. However, if the TMPDIR environment variable is not set or is set to an invalid directory, the function will fall back to the default temporary directory location, which is /tmp on most systems. In your case, since you are using XAMPP, the TMPDIR environment variable is likely set to /opt/lampp/temp/. This is why the temporary file is being written to that directory first. If you want to avoid writing the temporary file to the /opt/lampp/temp/ directory, you can explicitly specify the desired location using the sys_get_temp_dir() function, as shown in the previous response. This will ensure that the temporary file is written directly to the specified location. 3. Что Вы думаете по этому поводу? Возможно, мы тут во Франконии совсем verrückt стали....
Nichts zu danken! Ответ посмотрел. Всё должно быть в РHP. Предполагаю, что проблем не было, если бы Вы создавали в РHP скрипте директории и записывали в них файлы. Проверял Ваш скрипт на Open Server Panel. Можете попробовать скачать и установить под Windows. https://ospanel.io/download/ Устанавливал на Open Server проекты с ностингов hetzner (BayernsBest 50) https://www.hetzner.com и с IONOS (1&1) https://www.ionos.de/ Без проблем. Для экспорта больших БД МySQL в OpenServer (150Мb) использую утилиту heidisql https://www.heidisql.com/download.php Удачи! p.s. “You can never tell which way the train went by looking at the track.” Murphy's Law
Thanks, но все равно идею про PHP не понимаю. Но на выходных попробую. У меня все это пока дома, сайт (другой) на strato.de Когда сайт туда переносил были кое-какие проблемы, сейчас все фурычит. Да, Мерфи и Паркинсонвсегда приятны для интеллекта и эмоций.
В общем все совсем не ясно. 1. Предполагалось, что связано так или иначе с сервером. 2. Решил просто без загрузки просто уменьшить фотографию (если размер больше 1200000) и записать в тот же каталог с новым именем. 3. Новый файл (фото) не должен быть меньше 500 Кб.Текст внизу. 4. Текст внизу. Проблемы 1. Получается сжатый очень сильно файл ( около 1 Кб). 2. При попытке "сделать" его больше сообщение - Compressing image: /home/vlm/SERVER/gallery/Art/Normal/20230914_130006.jpgFailed rescale to min. 0.5MB: /home/vlm/SERVER/gallery/Art/Normal/20230914_130006_compressed.jpg Actual size: 6x4Removed compressed file: /home/vlm/SERVER/gallery/Art/Normal/20230914_130006_compressed.jpgCompressing image: /home/vlm/SERVER/gallery/Art/Normal/20230919_122343.jpgFailed rescale to min. 0.5MB: /home/vlm/SERVER/gallery/Art/Normal/20230919_122343_compressed.jpg Actual size: 16x13Removed compressed file: /home/vlm/SERVER/gallery/Art/Normal/20230919_122343_compressed.jpgCompressing image: /home/vlm/SERVER/gallery/Art/Normal/28878633912_13b6604323_o.jpgFailed rescale to min. 0.5MB: /home/vlm/SERVER/gallery/Art/Normal/28878633912_13b6604323_o_compressed.jpg 3. Это происходит так как владельцем нового файла стал daemon и прав read/wright для других не дано. 4. Пришли к той же проблеме - откуда появился демон и почему он крадет мой личный файл. ????? PHP: <?php declare ( strict_types=1 ); ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); ///// Function: compress and resize picture //////// function compressImage($sourceImagePath, $targetImagePath) { $imageInfo = getimagesize($sourceImagePath); if ($imageInfo['mime'] === 'image/jpeg') { $image = imagecreatefromjpeg($sourceImagePath); } else if ($imageInfo['mime'] === 'image/png') { $image = imagecreatefrompng($sourceImagePath); } else if ($imageInfo['mime'] === 'image/gif') { $image = imagecreatefromgif($sourceImagePath); } $originalImageSize = $imageInfo[0] * $imageInfo[1]; $minCompressedImageSize = 500000; // 0.5MB if ($originalImageSize <= $minCompressedImageSize) { // Skip compression if the original image size is less than or equal to 0.5MB echo "Skipping compression for image: {$sourceImagePath}"; } $compressionFactor = $minCompressedImageSize / $originalImageSize; $width = (int) ($imageInfo[0] * $compressionFactor); $height = (int) ($imageInfo[1] * $compressionFactor); $compressedImage = imagescale($image, $width, $height); if (filesize($targetImagePath) < (int) $minCompressedImageSize) { ///// Rescale the image: min 0.5MB $rescaledImage = imagescale($compressedImage, (int) ($originalImageSize / $minCompressedImageSize)); imagejpeg($rescaledImage, $targetImagePath, 90); imagedestroy($rescaledImage); ///// Size control///// $imageInfo = getimagesize($targetImagePath); if ($imageInfo[0] * $imageInfo[1] < (int) $minCompressedImageSize) { echo "Failed rescale to min. 0.5MB: {$targetImagePath}"; echo "<br>Actual size: {$imageInfo[0]}x{$imageInfo[1]}"; imagedestroy($compressedImage); echo "Removed compressed file: {$targetImagePath}"; } else { echo "Success !!!: {$targetImagePath}"; } } else { imagejpeg($compressedImage, $targetImagePath, 40); echo "Success !!: {$targetImagePath}"; } imagedestroy($image); imagedestroy($compressedImage); } ////////////// END Of Fonction ////////////////// $targetDirectory = '/home/vlm/SERVER/gallery/Art/Normal'; if (is_dir($targetDirectory)) { foreach (glob("{$targetDirectory}/*.jpg") as $sourceImagePath) { $targetImagePath = str_replace(".jpg", "_compressed.jpg", $sourceImagePath); $size = filesize($sourceImagePath); if ($size > 1200000) { // Check if image size exceeds 2MB echo "Compressing image: {$sourceImagePath}"; compressImage($sourceImagePath, $targetImagePath); } } echo " Compressed successfully!"; } else echo 'No Dir !!!';
Добрый день и с наступающим Новым Годом! Извините, не было времени глубоко бурить, но обратил внимание на то, что Вы применили функцию imagescale с двумя параметрами так PHP: $rescaledImage = imagescale($compressedImage, (int) ($originalImageSize / $minCompressedImageSize)); Второй параметр д.б. width, а ширина определятся как-то странно. Вам не кажется? Удачи!
Вас тоже с Новым Годом и всего наилучшнго !!! PHP: [LIST=1] [*]$rescaledImage = imagescale($compressedImage, (int) ($originalImageSize / $minCompressedImageSize)); [/LIST] Насколько я понимаю, это корректно. Берем ширину исходного изображения, чтобы определить новую ширину сжатого изображения. Высота по идее должна автоматически отрегулироваться для сохранения исходного соотношения сторон.
PHP: $originalImageSize = $imageInfo[0] * $imageInfo[1] // ширину * высоту = площадь изображения $minCompressedImageSize = 500000; // 0.5MB мин. размер файла в Кв Для того, чтобы скалировать изображение нужно так вычислить новую ширину: PHP: $rescaledImage = imagescale($compressedImage, (int) ($originalImageWidth * $kScale)); Однако, Вы не получите $kScale разделив площадь изображения на размер файла.
У вас по коду $minCompressedImageSize это килобайты, а $originalImageSize это площадь в пикселях, как вообще это можно сравнивать? Вы делите квадратные метры на килограммы.
Конечно нельзя так сравнивать. Однако, если поделить две площади изображения или два размера файла желаемая ширина всё равно не получится.
1. Так я же ищу соотношение, да, делить яблоки на груши физическая бессмыслица, но соотношение я получу, то есть например, если исходное изображение имеет площадь 100 000 пикселей, а минимальный размер сжатого изображения 500 КБ, то ($originalImageSize / $minCompressedImageSize) будет иметь значение 200, что означает, что масштабированное изображение должно иметь площадь 200 000 пикселей. Таким образом, сжатый файл будет иметь минимальный размер 500 КБ. 2. ГЛАВНОЕ. Черт с ним, с коэффициентом. У меня вопрос(проблема) с Демоном. Откуда, почему он берется? Может это быть связано с GD библиотекой? То ест вот это - 2. При попытке "сделать" его больше сообщение - Compressing image: /home/vlm/SERVER/gallery/Art/Normal/20230914_130006.jpgFailed rescale to min. 0.5MB: /home/vlm/SERVER/gallery/Art/Normal/20230914_130006_compressed.jpg Actual size: 6x4Removed compressed file: /home/vlm/SERVER/gallery/Art/Normal/20230914_130006_compressed.jpgCompressing image: /home/vlm/SERVER/gallery/Art/Normal/20230919_122343.jpgFailed rescale to min. 0.5MB: /home/vlm/SERVER/gallery/Art/Normal/20230919_122343_compressed.jpg Actual size: 16x13Removed compressed file: /home/vlm/SERVER/gallery/Art/Normal/20230919_122343_compressed.jpgCompressing image: /home/vlm/SERVER/gallery/Art/Normal/28878633912_13b6604323_o.jpgFailed rescale to min. 0.5MB: /home/vlm/SERVER/gallery/Art/Normal/28878633912_13b6604323_o_compressed.jpg 3. Это происходит так как владельцем нового файла стал daemon и прав read/wright для других не дано. 4. Пришли к той же проблеме - откуда появился демон и почему он крадет мой личный файл. ?????
Вы можете сменить пользователя от которого работает Апач (а вместе с ним и php если у вас конфигурация по-умолчани) в файле /opt/lampp/etc/httpd.conf (директивы User и Group), или вы можете добавить пользователя daemon в свою группу и разрешить в директории запись всем кто в группе: 775. Две несравнимые величины не могут иметь никакой пропорции. Даже если вы считаете что получаете какую-то пропорцию, то передавать её как ширину абсолютно бесмысленно. Так же бесмысленно и сама идея растягивать уменьшенный файл обратно, потому что качество уже не вернешь - получится мазня.
1. Спасбо 2. Да, видимо Вы правы что касается сжатия\расширения. 3. Здесь все равно не врубаюсь. Почему при других операциях во всех других программах (включая мои программы на РНР) где происходит создание, перемещение, изменение файлов все работает штатно. Не меняется владелец файла, прежде всего. В упор не понимаю.