Быстрый Дистанционный PHP Техника Обнаружения Изображения 404 - PullRequest
1 голос
/ 18 апреля 2010

Какой метод PHP-скрипта работает быстрее всего при обнаружении, если удаленное изображение не существует до того, как я включу изображение? Я имею в виду, я не хочу загружать все байты удаленного образа - достаточно, чтобы определить, существует ли он.

И хотя по этому вопросу, но с небольшим отклонением, я хотел бы загрузить достаточно байтов для определения информации о ширине и высоте JPEG.

Скорость очень важна в моей заботе о конструкции системы, над которой я работаю.

Ответы [ 6 ]

3 голосов
/ 05 января 2011

Я изменил код @ Volomike, чтобы получить ширину. Вот, пожалуйста ...


function get_image_dim($sURL) {
  // note that for jpeg you may need to change 300 to a larger value,
  // as some height/width info is farther out in the header
  try {
    $hSock = @ fopen($sURL, 'rb');
    if ($hSock) {
      while(!feof($hSock)) {
        $vData = fread($hSock, 300);
        break;
      }
      fclose($hSock);
      if (strpos(' ' . $vData, 'JFIF')>0) {
        $vData = substr($vData, 0, 300);
        $asResult = unpack('H*',$vData);        
        $sBytes = $asResult[1];
        $width = 0;
        $height = 0;
        $hex_width = '';
        $hex_height = '';
        if (strstr($sBytes, 'ffc2')) {
          $hex_height = substr($sBytes, strpos($sBytes, 'ffc2') + 10, 4);
          $hex_width = substr($sBytes, strpos($sBytes, 'ffc2') + 14, 4);
        } else {
          $hex_height = substr($sBytes, strpos($sBytes, 'ffc0') + 10, 4);
          $hex_width = substr($sBytes, strpos($sBytes, 'ffc0') + 14, 4);
        }
        $width = hexdec($hex_width);
        $height = hexdec($hex_height);
        return array('width' => $width, 'height' => $height);
      } elseif (strpos(' ' . $vData, 'GIF')>0) {
        $vData = substr($vData, 0, 300);
        $asResult = unpack('h*',$vData);
        $sBytes = $asResult[1];
        $sBytesH = substr($sBytes, 16, 4);
        $height = hexdec(strrev($sBytesH));
        $sBytesW = substr($sBytes, 12, 4);
        $width = hexdec(strrev($sBytesW));
        return array('width' => $width, 'height' => $height);
      } elseif (strpos(' ' . $vData, 'PNG')>0) {
        $vDataH = substr($vData, 22, 4);
        $asResult = unpack('n',$vDataH);
        $height = $asResult[1];        
        $vDataW = substr($vData, 18, 4);
        $asResult = unpack('n',$vDataW);
        $width = $asResult[1];        
        return array('width' => $width, 'height' => $height);
      }
    }
  } catch (Exception $e) {}
  return FALSE;
}

Итак, используя его, мы имеем ...


// jpeg
$url = 'http://upload.wikimedia.org/wikipedia/commons/thumb/c/ce/Quality_comparison_jpg_vs_saveforweb.jpg/250px-Quality_comparison_jpg_vs_saveforweb.jpg';
// png
//$url = 'http://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png';
// gif
//$url = 'http://upload.wikimedia.org/wikipedia/commons/e/e2/Sunflower_as_gif_small.gif';

$dim = get_image_dim($url);
print_r($dim);
3 голосов
/ 18 апреля 2010

Запустите cURL, который выполняет HEAD запрос, заполненный полным GET

Я не проверял это, но, надеюсь, вы поймете:

<?php
$url = 'http://www.example.com/image.gif';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_NOBODY, true); // this is what sets it as HEAD request
curl_exec($ch);

if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') { // 200 = OK
    // image exists ..
}

curl_close($ch);
?>

См. документация cURL для получения дополнительной информации о cURL.

2 голосов
/ 18 апреля 2010

Вы должны иметь возможность определять размеры JPEG, не загружая все его содержимое. Для базовых JPEG, то есть JPEG без прогрессивной развертки, сканируйте в байтах, пока не встретите 0xFFC0. Пропустить следующие три байта. Следующие два байта указывают высоту. За ними следуют еще два байта, которые указывают ширину.

Например, в «FF C0 00 11 08 01 DE 02 D0» 01DE представляет высоту 478, а 02D0 представляет ширину 720.

1 голос
/ 18 апреля 2010

Я бы отправил запрос GET, содержащий заголовок RANGE , чтобы ограничить фактическую передачу данных, где это возможно (удаленный сервер может не выполнить запрос RANGE, но его все же стоит попробовать). Вероятно, не имеет большого значения, используете ли вы сокеты (напрямую) или curl для выполнения запросов. Но ... ты никогда не узнаешь без эталонов. Для curl посмотрите на опцию "CURLOPT_RANGE" в http://docs.php.net/function.curl-setopt

Возможно, он не соответствует вашему профилю («несколько часов в час, на сервере с доступной только небольшой мощностью процессора»), но вы можете попробовать обрабатывать несколько URL-адресов одновременно, то есть иметь несколько активных соединений и обрабатывать только те, которые не будут блокировать операцию чтения. Если ограничивающим фактором является в основном / только мощность процессора ... забудьте эту часть. сокеты : взгляните на stream_select curl : см. curl_multi_exec ()

Если модуль curl недоступен, вы также можете использовать оболочку http url в сочетании с stream_context_create () для отправки запроса, содержащего заголовок RANGE.

Похоже, вы уже выяснили, что делать с данными после их получения.

0 голосов
/ 18 апреля 2010

Я думаю, что следующая процедура извлечет только высоты изображения для JPG, GIF и PNG или вернет условие === FALSE для 404 или другого типа изображения. Подпрограмма также делает это с наименьшими ресурсами сервера, потому что маршрут file_get_contents (), по-видимому, фактически загружает файл даже с добавленным ограничением байтов, как и getimagesize () загружает файл. Вы можете увидеть снижение производительности по сравнению с этим.

Эта процедура работает так, что она загружает из файла всего 300 байт. К сожалению, JPEG выталкивает свое значение высоты довольно далеко в файле, в отличие от GIF или PNG, и поэтому мне пришлось читать этот файл в байтах. Затем, с этими байтами, он ищет JFIF, PNG или GIF в этом заголовке, чтобы сообщить нам, какой это тип файла. Получив это, мы используем уникальные подпрограммы для каждого из них, чтобы проанализировать заголовок. Обратите внимание, что JPEG должен сначала использовать unpack () с H *, а затем сканировать для ffc2 или ffc0 и обрабатывать. GIF, однако, должен сначала распаковать () с h * (большая разница там).

Эта функция была создана мной методом проб и ошибок и может быть неправильной. Я запустил его на нескольких изображениях, и он, кажется, работает хорошо. Если вы найдете в этом ошибку, рассмотрите возможность сообщить мне.

В любом случае, эта система позволит мне определить высоту изображения, сбросить изображение и найти другое, если оно слишком высокое. Для любого случайного изображения, которое я нахожу, я устанавливаю ширину в теге IMG HTML, и оно автоматически изменяет высоту, но выглядит хорошо, только если изображение находится под определенной высотой. Кроме того, он проверяет 404, чтобы увидеть, не было ли изображение, которое мне вернул другой сервер, не для изображения, которое больше не существует или которое запрещает межсайтовую связь. И так как я вручную устанавливаю изображения на фиксированную ширину, мне не важно читать ширину изображения. Вы можете адаптировать эту функцию и, как правило, смотреть на несколько маленьких байт вперед, чтобы найти ширину изображения.

function getImageHeight($sURL) {
  try {
    $hSock = @ fopen($sURL, 'rb');
    if ($hSock) {
      while(!feof($hSock)) {
        $vData = fread($hSock, 300);
        break;
      }
      fclose($hSock);
      if (strpos(' ' . $vData, 'JFIF')>0) {
        $vData = substr($vData, 0, 300);
        $asResult = unpack('H*',$vData);
        $sBytes = $asResult[1];
        if (strstr($sBytes, 'ffc2')) {
          $sBytes = substr($sBytes, strpos($sBytes, 'ffc2') + 10, 4);
        } else {
          $sBytes = substr($sBytes, strpos($sBytes, 'ffc0') + 10, 4);
        } 
        return hexdec($sBytes);
      } elseif (strpos(' ' . $vData, 'GIF')>0) {
        $vData = substr($vData, 0, 300);
        $asResult = unpack('h*',$vData);
        $sBytes = $asResult[1];
        $sBytes = substr($sBytes, 16, 4);
        $sBytes = strrev($sBytes);
        return hexdec($sBytes);
      } elseif (strpos(' ' . $vData, 'PNG')>0) {
        $vData = substr($vData, 22, 4);
        $asResult = unpack('n',$vData);
        $nHeight = $asResult[1];
        return $nHeight;
      }
    }
  } catch (Exception $e) {}
  return FALSE;
}
0 голосов
/ 18 апреля 2010

Храните изображения локально. Это очень простое и гарантированное решение.

...