照片网上商店
Photo Online Store
我必须为我的组织创建一个具有一些附加功能的照片在线商店。但主要想法是允许用户上传他们的数码照片(仅限 JPEG 格式)并在商店中出售。该项目与 iStockPhotos、Fotolia 等网站有很大关系...
JPEG 图片是否有我应该遵循的标准,例如最小和最大尺寸以及质量?
我能够使用诸如 Imagine 之类的库从原始图像制作水印和缩略图。但我主要关心的是,如何将原始文件和重复文件安全地存储在适当的文件夹结构中,以及如何在有人购买原始文件时创建原始文件的下载链接?
我打算使用 PHP Yii2 框架从头开始构建它。所以请给我任何指导方针以使其成功。提前致谢。
我将把我的回答分成三个部分。上传、保存和 download-process。我希望你有使用 PHP 和 Yii2 的经验,所以我不会把整个事情都写出来,而是给你要点。
1。上传照片
这个很简单。只需创建一个表单,您就可以在其中上传您的 image-files。确保设置正确的加密类型 (multipart/form-data
)。 file-uploading 与 Yii2 的基础知识解释 here.
保存文件时需要执行两个步骤:
- 保存原件
- 创建一个调整大小并加水印的副本
对于第二个任务,我可以向您推荐库 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 中是否有一行将当前登录的用户链接到请求的照片。
如果连接可用,您就可以输出照片了。这包括两个步骤:
- 配置输出照片的响应
- 实际输出
响应配置
您可以完全手动或 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,因为它肯定有它的问题!
我必须为我的组织创建一个具有一些附加功能的照片在线商店。但主要想法是允许用户上传他们的数码照片(仅限 JPEG 格式)并在商店中出售。该项目与 iStockPhotos、Fotolia 等网站有很大关系...
JPEG 图片是否有我应该遵循的标准,例如最小和最大尺寸以及质量?
我能够使用诸如 Imagine 之类的库从原始图像制作水印和缩略图。但我主要关心的是,如何将原始文件和重复文件安全地存储在适当的文件夹结构中,以及如何在有人购买原始文件时创建原始文件的下载链接?
我打算使用 PHP Yii2 框架从头开始构建它。所以请给我任何指导方针以使其成功。提前致谢。
我将把我的回答分成三个部分。上传、保存和 download-process。我希望你有使用 PHP 和 Yii2 的经验,所以我不会把整个事情都写出来,而是给你要点。
1。上传照片
这个很简单。只需创建一个表单,您就可以在其中上传您的 image-files。确保设置正确的加密类型 (multipart/form-data
)。 file-uploading 与 Yii2 的基础知识解释 here.
保存文件时需要执行两个步骤:
- 保存原件
- 创建一个调整大小并加水印的副本
对于第二个任务,我可以向您推荐库 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 中是否有一行将当前登录的用户链接到请求的照片。
如果连接可用,您就可以输出照片了。这包括两个步骤:
- 配置输出照片的响应
- 实际输出
响应配置
您可以完全手动或 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,因为它肯定有它的问题!