Как передать файл на PHP?

200
28 марта 2019, 00:00

Есть смартфоновое приложение, которое загружает с сервера картинки. Появилась необходимость вносить изменения в адрес запроса, чтобы на смартфон загружались другие картинки.

Для этого я попробовал сделать так, чтобы запрос отправлялся не напрямую серверу, а через посредника: через свой php-сайт, который бы генерировал новый url, загружал по нему нужную картинку и передавал ее на обратно смартфон.

Проблема в том, что на стороне клиента не нормальный браузер, а мобильное приложение. Если точнее - gps навигатор. И он ни и в какую не хочет принимать картинки от моего php-конвертера, в то время, как браузер с компьютера прекрасно показывает страничку с нужной картинкой.

Пробовал загружать и отдавать картинку несколькими способами, но результат один: до браузера компьютера новая картинка доходит, а до приложения на смартфоне нет.

Вот несколько примеров по скачиванию файла https://a.tile.openstreetmap.org/0/0/0.png. Если что, то при подключении напрямую по этому url смартфон его прекрасно открывает.

Сначала пробовал просто возвращать картинку через echo

<?php 
    header ('Content-type: image/png');
    $ResultURL = 'https://a.tile.openstreetmap.org/0/0/0.png';
    $content = file_get_contents ($ResultURL);
    echo $content;
?>

Потом пробовал такой пример с хабра. Это - функция, которая вызывает окно скачивания файла.

<?php
  function file_force_download($file) {
     $file_headers = @get_headers($file);

    if ($file_headers[0] != 'HTTP/1.1 404 Not Found') {
        // сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт
        // если этого не сделать файл будет читаться в память полностью!
        if (ob_get_level()) {
            ob_end_clean();
        }
        // заставляем браузер показать окно сохранения файла
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename=' . basename($file));
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        // пришлось отключить эту строку:
        // с ней почему-то скачивался файл в ноль байт.
        //header('Content-Length: ' . filesize($file)); 
        // читаем файл и отправляем его пользователю
        readfile($file);
        exit;
        } else {
            echo 'file not found';
        }
    }

    file_force_download("https://a.tile.openstreetmap.org/0/0/0.png");
?>

Затем нашел на гитхабе простенький прокси и попробовал передать через него напрямую и файл и его теги.

<?php 
/**
 * Простой прокси-сервер на PHP для изучения и модификации данных, 
 * передаваемых между браузером и сторонним сервером.
 * 
 * Запуск: 
 *
 * указать URL сайта в $base
 * php -S 127.0.0.1:9001 proxy.php
 *
 * После этого в браузере можно открывать http://127.0.0.1:9001/
 * и все запросы пойдут через прокси на указанный в $base адрес.
 */
// Для вывода данных в консоль
$stderr = fopen('php://stderr', 'w');
$url = $_SERVER['REQUEST_URI'];
$path = parse_url($url, PHP_URL_PATH);
$query = parse_url($url, PHP_URL_QUERY);
$newPath = ltrim($path, '/');
if ($query) {
    $newPath .= '?' . $query;
}
//$base = 'https://someapprentice.github.io/maintaskforlayout/';
//$proxyUrl = $base . $newPath;
$base = 'https://a.tile.openstreetmap.org/0/0/0.png';
$proxyUrl = $base;
$contents = @file_get_contents($proxyUrl /* , false, $context */);
// Получаем заголовки ответа из глобальной переменной (PHP!)
$headers = $http_response_header;
$firstLine = $headers[0];

if ($contents === false) {
    fwrite($stderr, "Request failed: $proxyUrl - $firstLine\n");
    header("HTTP/1.1 503 Proxy error");
    die("Proxy failed to get contents at $proxyUrl");
}

fwrite($stderr, "$proxyUrl - OK: $firstLine\n");
$allowedHeaders = "!^(http/1.1|server:|content-type:|last-modified|access-control-allow-origin|Content-Length:|Accept-Ranges:|Date:|Via:|Connection:|X-|age|cache-control|vary)!i";
// Прокидываем разрешенные заголовки
foreach ($headers as $header) {
    if (preg_match($allowedHeaders, $header)) {
        fwrite($stderr, "+ $header\n");
        header($header);
    } else {
        fwrite($stderr, "- $header\n");        
    }
}
echo $contents;

Но ничего не вышло.

Вопрос: что я делаю не так? И как все-таки правильно передавать файлы на php?

PS: Вообще, есть такая мысль, что может буть нужно просто создать для телефона иллюзию, что мой сайт это не сайт вовсе, а сервер с файлами и просто передавать телефону заголовки от настоящего сервера. Только вот как это сделать?

Answer 1

В общем, я сам разобрался.

Мой php-скрипт был на бесплатном хостинге Beget.tech. И, видимо, они производят какие-то манипуляции с заголовками, в результате чего страничка на смартфоне не загружается.

Проблема решилась переездом на другой бесплатный хостинг. Пока что я остановился на Hostiman.ru - там со смартфонами все работает.

А для возврата картинки пользователю стал использовать два метода.

Вариант быстрый. Если изображение не требует обработки, то я просто отсылаю пользователя на новый URL через редирект.

header('Location: ' . $url, true, 302);

Заметил, что приложение на смартфоне умеет обрабатывать всего несколько кодов ответов: 200, 302, 404. Все остальные он тупо обрывает.

Вариант медленный. Чтобы обработать картинку, нужно сначала загрузить ее на сервер.

function load($imageURL) {
    $info   = getimagesize($imageURL);
    $type   = $info[2];
    $width  = $info[0];
    $height = $info[1];

    switch ($type) { 
        case 1: 
            $loadedImage = imageCreateFromGif($imageURL);
            imageSaveAlpha($img, true);
            break;                    
        case 2: 
            $loadedImage = imageCreateFromJpeg($imageURL);
            break;
        case 3: 
            $loadedImage = imageCreateFromPng($imageURL); 
            imageSaveAlpha($loadedImage, true);
            break;
    }
    $imageData = [$loadedImage, $type, $width, $height];
    return $imageData; 
}

Дальше можно выполнять все необходимые преобразования картинки. Однако многие преобразования требуют указывать размер изображения. Чтобы каждый раз не обращаться к файлу, я считываю все необходимые данные при загрузке и отправляю вместе с картинкой в своеобразном пакете $imageData.

После этого можно выводить обработанное изображение пользователю.

function output($imageData, $src) {
    $image =  $imageData[0];
    $type   = $imageData[1];
    switch ($type) {
    case 1:
        header('Content-Type: image/gif'); 
        imageGif($image, $src);
        break;            
    case 2:
        header('Content-Type: image/jpeg');
        imageJpeg($image, $src, 100);
        break;            
    case 3:
        header('Content-Type: image/x-png');
        imagePng($image, $src);
        break;
    }
    imagedestroy($image);
    readfile($src);
    exit();
}
READ ALSO
Ошибка в PHP &ldquo;Object of a class couldn&#39;t be converted to a string&rdquo;

Ошибка в PHP “Object of a class couldn't be converted to a string”

Всем привет! Столкнулся со странной для меня ошибкой, имеется код:

152
Как прибавить число к последнему числу в строке

Как прибавить число к последнему числу в строке

Есть какое то определенное значение, получаю последнее в нем число, если оно есть прибавляю к нему 1

160
Чат на php и mysql

Чат на php и mysql

Пишу чат на php, сообщения отправляются в базу данных mysql и получается достать их оттуда, но проблема в том, что не получается вывести email того...

163