利用PHP读取到图片的EXIF信息的方法是什么

发布时间:2021-10-29 09:34:19 作者:iii
来源:亿速云 阅读:151
# 利用PHP读取到图片的EXIF信息的方法是什么

## 目录
1. [EXIF基础概念](#exif基础概念)
2. [PHP环境准备](#php环境准备)
3. [核心函数exif_read_data详解](#核心函数exif_read_data详解)
4. [实战案例解析](#实战案例解析)
5. [常见问题解决方案](#常见问题解决方案)
6. [高级应用技巧](#高级应用技巧)
7. [安全注意事项](#安全注意事项)
8. [性能优化建议](#性能优化建议)
9. [完整代码示例](#完整代码示例)
10. [总结与扩展](#总结与扩展)

## EXIF基础概念
EXIF(Exchangeable Image File Format)是可交换图像文件格式的简称,它由日本电子工业发展协会(JEIDA)制定,主要用于数码相机记录的元数据标准。

### EXIF包含的主要信息类型
- **相机信息**:制造商、型号、序列号
- **拍摄参数**:光圈值、快门速度、ISO感光度
- **日期时间**:照片创建和修改时间
- **GPS数据**:经纬度坐标、海拔高度
- **版权信息**:作者、版权声明
- **缩略图**:嵌入式预览图像

### EXIF数据结构示例
```plaintext
[FileName] => sample.jpg
[FileDateTime] => 1645729200
[FileSize] => 2456789
[FileType] => 2
[MimeType] => image/jpeg
[SectionsFound] => ANY_TAG, IFD0, EXIF
[COMPUTED] => Array
    (
        [html] => width="4000" height="3000"
        [Height] => 3000
        [Width] => 4000
        [IsColor] => 1
    )
[Make] => Canon
[Model] => EOS 5D Mark IV
[Orientation] => 1
[XResolution] => 72/1
[YResolution] => 72/1
[ResolutionUnit] => 2
[Software] => Adobe Photoshop 22.0
[DateTime] => 2021:12:25 15:30:22
[Exif_IFD_Pointer] => 246
[GPS_IFD_Pointer] => 978

PHP环境准备

必备扩展检查

在开始之前,需要确保PHP环境已启用EXIF扩展:

php -m | grep exif

或在PHP文件中使用:

<?php
echo extension_loaded('exif') ? 'EXIF扩展已加载' : 'EXIF扩展未加载';

php.ini配置要求

确保以下配置项已正确设置:

; 启用EXIF扩展
extension=exif

; 允许读取远程文件(非必须,谨慎开启)
allow_url_fopen = On

; 内存限制建议(处理大图时需要)
memory_limit = 128M

兼容性说明

核心函数exif_read_data详解

函数原型

array|false exif_read_data(
    string $filename,
    string|null $sections = null,
    bool $arrays = false,
    bool $thumbnail = false
)

参数深度解析

  1. $filename

    • 支持本地文件路径(/path/to/image.jpg
    • 支持URL(需要allow_url_fopen开启)
    • 支持流资源(PHP 7.2+)
  2. $sections(控制读取的段)

    • NULL:读取所有可用段(默认)
    • 'FILE':基础文件信息
    • 'COMPUTED':计算得出的属性
    • 'IFD0':主图像目录
    • 'THUMBNL':缩略图信息
    • 'COMMENT':用户注释
    • 'EXIF':EXIF专用数据
  3. $arrays

    • false:返回平面数组(默认)
    • true:分层返回数组结构
  4. $thumbnail

    • false:不提取缩略图(默认)
    • true:尝试提取嵌入式缩略图

返回值说明

实战案例解析

基础读取示例

$exif = exif_read_data('photo.jpg');
echo "<pre>";
print_r($exif);
echo "</pre>";

// 获取拍摄时间
if(isset($exif['DateTimeOriginal'])){
    echo "拍摄时间: ".$exif['DateTimeOriginal'];
}

// 获取GPS坐标
if(isset($exif['GPSLatitude']) && isset($exif['GPSLongitude'])){
    $lat = gpsToDecimal($exif['GPSLatitude'], $exif['GPSLatitudeRef']);
    $lon = gpsToDecimal($exif['GPSLongitude'], $exif['GPSLongitudeRef']);
    echo "位置: $lat, $lon";
}

function gpsToDecimal($coord, $hemi) {
    $degrees = count($coord) > 0 ? $coord[0] : 0;
    $minutes = count($coord) > 1 ? $coord[1] : 0;
    $seconds = count($coord) > 2 ? $coord[2] : 0;
    
    $flip = ($hemi == 'W' || $hemi == 'S') ? -1 : 1;
    return $flip * ($degrees + $minutes / 60 + $seconds / 3600);
}

批量处理目录图片

function processDirectory($path) {
    $files = scandir($path);
    $results = [];
    
    foreach ($files as $file) {
        if(in_array($file, ['.', '..'])) continue;
        
        $fullPath = $path.'/'.$file;
        if(exif_imagetype($fullPath) === IMAGETYPE_JPEG) {
            $exif = @exif_read_data($fullPath);
            if($exif !== false) {
                $results[$file] = [
                    'size' => $exif['FileSize'] ?? 0,
                    'camera' => ($exif['Make'] ?? '').' '.($exif['Model'] ?? ''),
                    'date' => $exif['DateTimeOriginal'] ?? null
                ];
            }
        }
    }
    
    return $results;
}

$photoStats = processDirectory('/images');
print_r($photoStats);

高级示例:创建EXIF查看器

class ExifViewer {
    private $supportedTypes = [
        IMAGETYPE_JPEG => 'JPEG',
        IMAGETYPE_TIFF_II => 'TIFF',
        IMAGETYPE_TIFF_MM => 'TIFF'
    ];
    
    public function displayExif($imagePath) {
        if(!file_exists($imagePath)) {
            throw new Exception("文件不存在");
        }
        
        $type = exif_imagetype($imagePath);
        if(!array_key_exists($type, $this->supportedTypes)) {
            throw new Exception("不支持的图像格式");
        }
        
        $exif = @exif_read_data($imagePath, 0, true);
        if($exif === false) {
            throw new Exception("无法读取EXIF数据");
        }
        
        $this->renderTable($exif);
    }
    
    private function renderTable($exifData) {
        echo '<table border="1" cellpadding="5">';
        foreach($exifData as $section => $sectionData) {
            echo "<tr><th colspan='2' style='background:#eee'>$section</th></tr>";
            foreach($sectionData as $key => $value) {
                echo "<tr><td>$key</td><td>";
                if(is_array($value)) {
                    echo implode(', ', array_map('htmlspecialchars', $value));
                } else {
                    echo htmlspecialchars($value);
                }
                echo "</td></tr>";
            }
        }
        echo '</table>';
    }
}

// 使用示例
try {
    $viewer = new ExifViewer();
    $viewer->displayExif('test.jpg');
} catch(Exception $e) {
    echo "错误: ".$e->getMessage();
}

常见问题解决方案

1. 中文乱码问题

EXIF信息中的文本可能使用不同编码:

function fixEncoding($str) {
    $encoding = mb_detect_encoding($str, ['ASCII','JIS','UTF-8','EUC-JP','SJIS']);
    return $encoding !== 'UTF-8' ? mb_convert_encoding($str, 'UTF-8', $encoding) : $str;
}

$exif = exif_read_data('photo.jpg');
$software = isset($exif['Software']) ? fixEncoding($exif['Software']) : '';

2. GPS坐标转换优化

更健壮的GPS处理函数:

function parseGps($exifCoord, $hemi) {
    for ($i = 0; $i < 3; $i++) {
        $part = explode('/', $exifCoord[$i]);
        if (count($part) == 1) {
            $exifCoord[$i] = $part[0];
        } else if (count($part) == 2) {
            $exifCoord[$i] = $part[0] / $part[1];
        } else {
            $exifCoord[$i] = 0;
        }
    }
    
    list($degrees, $minutes, $seconds) = $exifCoord;
    $flip = ($hemi == 'W' || $hemi == 'S') ? -1 : 1;
    return $flip * ($degrees + $minutes / 60 + $seconds / 3600);
}

3. 大文件处理技巧

使用内存优化方案:

function getLargeImageExif($path) {
    // 临时降低内存限制
    $originalLimit = ini_get('memory_limit');
    ini_set('memory_limit', '512M');
    
    try {
        $exif = exif_read_data($path);
    } finally {
        ini_set('memory_limit', $originalLimit);
    }
    
    return $exif;
}

高级应用技巧

1. 与图像处理库结合

使用GD库保存EXIF:

function resizeWithExif($srcPath, $dstPath, $maxWidth) {
    $exif = exif_read_data($srcPath);
    list($width, $height) = getimagesize($srcPath);
    
    $ratio = $maxWidth / $width;
    $newHeight = $height * $ratio;
    
    $image = imagecreatefromjpeg($srcPath);
    $newImage = imagecreatetruecolor($maxWidth, $newHeight);
    imagecopyresampled($newImage, $image, 0, 0, 0, 0, $maxWidth, $newHeight, $width, $height);
    
    // 保存EXIF数据
    $quality = 90;
    imagejpeg($newImage, $dstPath, $quality);
    
    // 使用pel库写入EXIF(需额外安装)
    if(class_exists('PelJpeg')) {
        $jpeg = new PelJpeg($dstPath);
        $exif = new PelExif();
        $jpeg->setExif($exif);
        $jpeg->saveFile($dstPath);
    }
}

2. 自定义EXIF写入

(注意:PHP原生不支持EXIF写入,需使用第三方库)

require_once 'Pel/autoload.php';

function writeCustomExif($imagePath, $data) {
    $jpeg = new PelJpeg($imagePath);
    $exif = new PelExif();
    $tiff = new PelTiff();
    $ifd0 = new PelIfd(PelIfd::IFD0);
    
    foreach ($data as $tag => $value) {
        $type = PelTag::getType($tag);
        $entry = new PelEntryAscii($tag, $value);
        $ifd0->addEntry($entry);
    }
    
    $tiff->setIfd($ifd0);
    $exif->setTiff($tiff);
    $jpeg->setExif($exif);
    $jpeg->saveFile($imagePath);
}

// 使用示例
writeCustomExif('photo.jpg', [
    PelTag::COPYRIGHT => 'Copyright 2023 My Company',
    PelTag::ARTIST => '张三'
]);

安全注意事项

1. 文件上传安全

function safeExifRead($tmpPath) {
    // 验证真实文件类型
    $finfo = new finfo(FILEINFO_MIME);
    $mime = $finfo->file($tmpPath);
    
    if(strpos($mime, 'image/jpeg') === false) {
        throw new Exception("仅支持JPEG格式");
    }
    
    // 禁用危险标签
    $exif = exif_read_data($tmpPath);
    unset($exif['GPSLatitude'], $exif['GPSLongitude']);
    
    return $exif;
}

2. 敏感信息过滤

function filterSensitiveExif($exifData) {
    $blacklist = [
        'GPSLatitude', 'GPSLongitude', 'GPSAltitude',
        'SerialNumber', 'MakerNote', 'UserComment'
    ];
    
    foreach ($blacklist as $key) {
        if (isset($exifData[$key])) {
            unset($exifData[$key]);
        }
    }
    
    return $exifData;
}

性能优化建议

  1. 缓存策略:对静态图片的EXIF数据进行缓存

    function getCachedExif($imagePath) {
       $cacheFile = 'cache/'.md5($imagePath).'.json';
       if(file_exists($cacheFile) && 
          filemtime($cacheFile) > filemtime($imagePath)) {
           return json_decode(file_get_contents($cacheFile), true);
       }
    
    
       $exif = exif_read_data($imagePath);
       file_put_contents($cacheFile, json_encode($exif));
       return $exif;
    }
    
  2. 延迟加载:仅当需要时才读取特定段 “`php // 只读取基础信息 $fileInfo = exif_read_data(‘photo.jpg’, ‘FILE’);

// 用户查看详情时再读取完整数据 if(\(needDetails) { \)fullExif = exif_read_data(‘photo.jpg’); }


3. **批量处理优化**:
   ```php
   function batchProcess($dir, $callback) {
       $files = new RecursiveIteratorIterator(
           new RecursiveDirectoryIterator($dir)
       );
       
       foreach ($files as $file) {
           if($file->isDir()) continue;
           if(exif_imagetype($file) !== IMAGETYPE_JPEG) continue;
           
           $exif = @exif_read_data($file);
           if($exif !== false) {
               $callback($file, $exif);
           }
       }
   }

完整代码示例

综合EXIF查看器

”`php <?php /** * 高级EXIF查看器 */ class AdvancedExifViewer { private $supportedFormats = [ IMAGETYPE_JPEG => ‘JPEG’, IMAGETYPE_TIFF_II => ‘TIFF (Intel)’, IMAGETYPE_TIFF_MM => ‘TIFF (Motorola)’ ];

public function display($imagePath) {
    try {
        $this->validate($imagePath);
        $exif = $this->readExifData($imagePath);
        $this->renderOutput($imagePath, $exif);
    } catch (Exception $e) {
        $this->renderError($e->getMessage());
    }
}

private function validate($path) {
    if(!file_exists($path)) {
        throw new Exception("指定的文件不存在");
    }

    $type = @exif_imagetype($path);
    if(!$type || !isset($this->supportedFormats[$type])) {
        throw new Exception("不支持的文件格式");
    }
}

private function readExifData($path) {
    $exif = @exif_read_data($path, null, true);
    if($exif === false) {
        throw new Exception("无法读取EXIF数据");
    }

    return $this->processExifData($exif);
}

private function processExifData($exif) {
    // 处理GPS数据
    if(isset($exif['GPS']['GPSLatitude']) && 
       isset($exif['GPS']['GPSLongitude'])) {
        $exif['COMPUTED']['GPSDecimal'] = [
            'lat' => $this->gpsToDecimal(
                $exif['GPS']['GPSLatitude'],
                $exif['GPS']['GPSLatitudeRef']
            ),
            'lng' => $this->gpsToDecimal(
                $exif['GPS']['GPSLongitude'],
                $exif['GPS']['GPSLongitudeRef']
            )
        ];
    }

    // 处理日期时间
    if(isset($exif['EXIF']['DateTimeOriginal'])) {
        $exif['EXIF']['DateTimeOriginal'] = 
            $this->formatExifDate($exif['EXIF']['DateTimeOriginal']);
    }

    return $exif;
}

private function gpsToDecimal($coord, $hemi) {
    $degrees = count($coord) > 0 ? $this->exifFractionToFloat($coord[0]) : 0;
    $minutes = count($coord) > 1 ? $this->exifFractionToFloat($coord[1]) : 0;
    $seconds =
推荐阅读:
  1. 安装php的exif扩展库
  2. php 获取图片的信息

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php

上一篇:如何进行Django框架urls.py路由设置

下一篇:Mysql数据分组排名实现的示例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》