如何使用原生PHP展示存储在Amazon S3中的已上传图片?
存在的两个核心问题
- 上传逻辑数据不匹配:上传到S3时使用的文件名为用户上传的原始文件名,写入数据库的
post_image字段时你将文件名重新赋值为了时间戳格式,二者完全不一致,后续根本找不到对应的S3文件 - 展示路径错误:当前图片标签指向的是本地服务器
images/目录,你的图片实际存储在S3中,自然无法加载
修复步骤
1. 修改add_post.php上传逻辑
推荐直接将S3返回的永久访问地址存入数据库,省去后续拼接地址的步骤,同时统一文件名避免重复,修改后代码如下:
if(isset($_POST['create_post'])){ if(!empty($_POST['post_contents'])){ $post_image_url = ''; if(isset($_FILES['image'])){ // 生成唯一文件名避免重名覆盖 $extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION); $file_name = date('YmdHis') . '.' . $extension; $temp_file_location = $_FILES['image']['tmp_name']; $s3 = new Aws\S3\S3Client([ 'region' => 'ap-northeast-1', 'version' => 'latest', 'credentials' => [ // 建议把密钥存在Heroku环境变量,不要硬编码在代码里 'key' => getenv('AWS_ACCESS_KEY_ID'), 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), ] ]); $result = $s3->putObject([ 'Bucket' => '替换为你的S3桶名', 'Key' => $file_name, 'SourceFile' => $temp_file_location, // 按需设置公共读权限,如果你的桶默认公共可访问可以不加 'ACL' => 'public-read' ]); // 获取S3返回的永久访问地址 $post_image_url = $result['ObjectURL']; } $post = $db->prepare('INSERT INTO posts SET post_user_id=?, post_contents=?, post_image=?, post_date=NOW()'); $post->execute(array( $user['user_id'], $_POST['post_contents'], // 直接存S3的完整访问地址 $post_image_url, )); header('Location: index.php'); exit(); }else{ echo "<script>alert('Contents fields cannot be empty')</script>"; } }
2. 修改index.php展示逻辑
直接输出数据库中存储的S3访问地址即可:
<?php foreach ($posts as $post): ?> <div class="post-preview"> <a href="post.php?post_id=<?php echo htmlspecialchars($post['post_id']); ?>"><?php echo htmlspecialchars($post['post_contents']); ?></a> <?php if(!empty($post['post_image'])): ?> <p><img width='300' src="<?php echo htmlspecialchars($post['post_image'], ENT_QUOTES); ?>"></p> <?php endif; ?> <p class="postContents"><?php echo htmlspecialchars($post['post_date'], ENT_QUOTES); ?> | <?php echo htmlspecialchars($post['user_name'], ENT_QUOTES); ?></p> <hr class="my-4" /> </div> <?php endforeach; ?>
补充注意事项
- 提前配置S3桶的CORS规则,允许你的Heroku域名访问资源,否则图片会被跨域策略拦截
- 如果不希望图片公开可访问,可以调用S3的
getObjectUrl方法生成临时签名的访问地址,输出到前端即可
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

