照片网上商店

Photo Online Store

我必须为我的组织创建一个具有一些附加功能的照片在线商店。但主要想法是允许用户上传他们的数码照片(仅限 JPEG 格式)并在商店中出售。该项目与 iStockPhotos、Fotolia 等网站有很大关系...

JPEG 图片是否有我应该遵循的标准,例如最小和最大尺寸以及质量?

我能够使用诸如 Imagine 之类的库从原始图像制作水印和缩略图。但我主要关心的是,如何将原始文件和重复文件安全地存储在适当的文件夹结构中,以及如何在有人购买原始文件时创建原始文件的下载链接?

我打算使用 PHP Yii2 框架从头开始构建它。所以请给我任何指导方针以使其成功。提前致谢。

我将把我的回答分成三个部分。上传、保存和 download-process。我希望你有使用 PHP 和 Yii2 的经验,所以我不会把整个事情都写出来,而是给你要点。

1。上传照片

这个很简单。只需创建一个表单,您就可以在其中上传您的 image-files。确保设置正确的加密类型 (multipart/form-data)。 file-uploading 与 Yii2 的基础知识解释 here.

保存文件时需要执行两个步骤:

  1. 保存原件
  2. 创建一个调整大小并加水印的副本

对于第二个任务,我可以向您推荐库 yurkinx/yii2-image,我使用它获得了非常好的体验。它内置了调整大小和水印功能。

2。保存照片

我通常将它们放在 @runtime 内的专用文件夹中。运行时文件夹在您的 project-root 中,因此无法从网络访问。您的文件夹可能有以下路径,您将其放入 params.php 供以后参考。

@runtime/shop_images/

对于实际的 file-names,您可以使用我将在接下来解释的模型 ID。您的 file-names 可能是:

  • 1.jpg(原文)
  • 1_thumb.jpg(调整大小并加水印的副本)

你应该有照片的模特。每张上传的照片将由此模型中的一行表示 db-table。您还需要一个 table 来连接用户和他们购买的图片 (m:n)。如果您需要确切的架构,请告诉我。

注意...您需要先创建 model-instance 并保存。否则你将没有 id 来命名实际文件!最简单的方法是覆盖你的 photo-model 的 save() 方法,因为 beforeSave() 太早(还没有 id!)而 afterSave() 太晚了(没有回滚的可能性) ).

3。正在下载照片

这个比听起来容易得多。您在 photo-conroller 中创建一个操作,让用户下载图片。

在操作中,您首先检查用户是否购买了图片。您可以轻松地做到这一点,因为您只需要检查 user_photo-table 中是否有一行将当前登录的用户链接到请求的照片。

如果连接可用,您就可以输出照片了。这包括两个步骤:

  1. 配置输出照片的响应
  2. 实际输出

响应配置

您可以完全手动或 use my extension 完成此操作。这是手动方式:

public function actionPicture($id) {
    //find the model (will throw excetion if not)
    $model = $this->findModel($id);

    //check if user is allowed
    if (!UserPhoto::find()->user(Yii::$app->user->id)->photo($model)->exists()) {
        //throw not allowed exception here!
    }

    //get the path to your photo
    $photoPath= Yii::getAlias('@runtime/shop_images') . DIRECTORY_SEPARATOR . $model->id . '.jpg');
    $photoPath= FileHelper::normalizaPath($imagePath);

    //prepare the response
    $response = Yii::$app->response;
    $response->headers->set('Content-type', 'image/jpg');
    $response->headers->set('Content-length', filesize($photoPath));
    $response->format = \yii\web\Response::FORMAT_RAW;

    //return the contents
    return file_get_contents($photoPath);
}

让您对此有所了解。无论您从操作中 return 做什么,都将放入您的响应的 data 属性中。然后将其格式化为响应的 content 属性。这将如何发生取决于您设置的响应格式。在我们的例子中,我们选择了 FORMAT_RAW ,它让数据保持原样。现在我们可以简单地 return 我们 photo-file 的内容,我们就完成了。

您可以通过指定额外的 headers 进一步指定文件的处理方式。例如,通过这种方式,您可以强制下载具有特定文件名的文件:

$headers->set('Content-disposition', 'attachment; filename="' . $myCustomFileName . '"');

与您为拇指创建动作或使用第二个参数扩展此动作的方式相同,第二个参数告诉您图像的大小 return。

希望能帮到你。如果您需要有关其中一个步骤的更多信息,请随时询问!

DB-Schema

这是创建所需的两个 table 的可能迁移。 user-table 被省略,因为您可能已经创建了这个。

public function up() {
    //the photo table and the relation to the owning user
    $this->createTable('{{%photo}}', [
        'id'=>$this->primaryKey(),
        'owner_user_id'=>$this->integer(),
        'original_filename'=>$this->string()->notNull(),
        'filesize'=>$this->integer()->notNull(),
        'extension'=>$this->string(4)->notNull(),
        'meta_data'=>$this->text(),
    ]);
    $this->addForeignKey('FK_photo_user', '{{%photo}}', 'owner_user_id', '{{%user}}', 'id', 'SET NULL', 'CASCADE');

    //the m:n-table mapping users to their purchased photos
    $this->createTable('{{%user_photo}}', [
        'user_id'=>$this->integer()->notNull(),
        'photo_id'=>$this->integer()->notNull(),
        'PRIMARY KEY (user_id, photo_id)',
    ]);
    $this->addForeignKey('FK_user_photo_user', '{{%user_photo}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');
    $this->addForeignKey('FK_user_photo_photo', '{{%user_photo}}', 'photo_id', '{{%photo}}', 'id', 'CASCADE', 'CASCADE');

    return true;
}

如果您查看架构,您就会明白要点。

Photo-metadata (EXIF)

如果您希望为照片保存 meta-data,通常是 EXIF-data,您当然也可以这样做。不过,我必须警告您……正如我目前在我们的一个项目中所体验的那样,相机制造商实际上并没有真正的标准来存储它们的价值。在我们的示例中,最重要的信息应该是 "date taken" 字段。仅此一项就可以在多个地方,具体取决于制造商。更复杂的是 EXIF 中的数据类型。我们在那里遇到了非法字符的大麻烦,几乎每个 charset-encoding 你能想象到的。

尽管如此,我会简要介绍一下我们如何将数据保存在 JSON-format 的文本列中。最大的优势是你拥有所有的原始结构。我还在上面的迁移中添加了该列。

$exif = exif_read_data($model->localFilePath, 'FILE,EXIF');
if ($exif !== false) {
    $model->meta_Data = Json::encode($exif);
}

确保您阅读了关于 exif_read_data()documentation,因为它肯定有它的问题!