1、创建my.php文件
//忽略用户断开
ignore_user_abort(true);
//设置文件最长执行时间
set_time_limit(300);
//查找未上传s3文件
header("content-type:text/html;charset=utf-8");
//传递参数,使用空格隔开
$db = DB_HOSTNAME .' '. DB_USERNAME .' '. DB_PASSWORD .' '. DB_DATABASE;
// python python程序路径(第二个子串为所要执行的python脚本的位置) 传递的参数(第三个子串为所需传入的参数不限个数,中间用空格分隔) 输出错误 2>&1
$python = "python ".PUBLIC_PATH."python/my.py 2>&1 ".$db;
exec($python, $message);
echo json_encode(['code' => 1, 'message' => $message]);
2、服务器必须全局安装python,并安装python需要用到的类库
# 这里用到了pymysql和boto3,所以提前安装好
pip install pymysql
pip install boto3
3、创建mysql.py,数据库连接文件
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 合并分片文件并上传AWS s3
import sys
import pymysql
try:
# 运行环境,通过php传递参数
Hostname = sys.argv[1]
userName = sys.argv[2]
password = sys.argv[3]
database = sys.argv[4]
except IndexError as e:
Hostname = "127.0.0.1"
userName = "root"
password = "123456"
database = 'test'
# 定义数据库查询方法
def mysql(sql='', dbtype=''):
try:
# 打开数据库连接
db = pymysql.connect(hostname, userName, password, database)
except:
print('数据库连接失败,10s后重试')
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
result = ()
try:
# 执行sql语句
cursor.execute(sql)
if dbtype == 'fetchall':
# 获取所有记录列表
result = cursor.fetchall()
elif dbtype == 'fetchone':
# 使用 fetchone() 方法获取单条数据.
result = cursor.fetchone()
elif dbtype == '':
# 提交到数据库执行 增,删,改
db.commit()
except:
print("Error: unable to fetch data")
# 关闭数据库连接
db.close()
return result
4、创建my.py,通过python程序合并分片文件,并上传AWS S3
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 合并分片文件并上传AWS s3
import os
import time
import boto3
import mysql
from urllib import parse
# 获取项目的绝对路径
curPath = os.path.abspath(os.path.dirname(__file__))
code = "fileId,uploadKey,categoryId,totalChunks,fileSuffix,filePath,rawName,fileType,fileTypeMime"
# 根据用户查询出加密字符串
sql = "select %s from file where fileS3 = 0 and s3Type = 0" % code
results = mysql.mysql(sql, 'fetchall')
if results != ():
AWS_ACCESS_KEY_ID = '自己的AWS_ACCESS_KEY_ID'
AWS_SECRET_ACCESS_KEY = '自己的AWS_SECRET_ACCESS_KEY'
AWS_BUCKET_NAME = '存储桶'
session = boto3.Session(
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
region_name='ap-southeast-1' # 这个必须加,不然会报错,此处根据自己的 s3 地区位置改变
)
s3 = session.client("s3")
client = session.client('cloudfront')
for row in results:
fileId = row[0]
uploadKey = row[1]
categoryId = row[2]
totalChunks = row[3]
fileSuffix = row[4] # 文件后缀
filePath = row[5]
rawName = row[6] # 文件原始名称 file_old_name
fileType = row[7]
fileTypeMime = row[8] # 上传文件的类型
where = "uploadKey = '%s' and fileId = 0" % uploadKey
fileNewName = rawName + '.' + fileSuffix # 文件新名称
uploadRelativePaths = filePath # 文件s3路径
fileS3path = uploadRelativePaths + fileNewName # S3路径 - 需要上传的文件本地路径
uploadAbsolutePath = curPath + uploadRelativePaths # 上传绝对路径
# if not os.path.exists(uploadAbsolutePath):
# os.makedirs(uploadAbsolutePath)
# 绝对路径 - 需要上传的文件本地路径
fileLocalPath = uploadAbsolutePath + fileNewName
if not os.path.exists(fileLocalPath): # 检测文件是否存在
if totalChunks != 1:
try:
fName = open(fileLocalPath, "wb+") # w以写方式打开,如果文件不存在则创建文件, r二进制
# 合并分片文件
i = 0
while i <= totalChunks:
i += 1
# 块文件名称
fileChunksName = uploadKey + "_chunk" + str(i) + "." + fileSuffix
# 文件块绝对路径
fileChunkAbsolutePath = curPath + 'chunk/' + fileChunksName
if os.path.exists(fileChunkAbsolutePath): # 检测文件是否存在
# 合并文件块
x = open(fileChunkAbsolutePath, "rb") # 打开列表中的文件,读取文件内容
fName.write(x.read()) # 写入新建的文件中
x.close() # 关闭列表文件
# 删除文件块
os.remove(fileChunkAbsolutePath)
fName.close() # 关闭列表文件
except: # FileNotFoundError as e
print('合并分片文件发生了异常')
if os.path.exists(fileLocalPath): # 检测文件是否存在
# s3上传状态更新成上传中
# 更新文件表,文件已合成,正在处理上传
sql = "UPDATE file SET s3Type = 1 WHERE fileId = %d" % fileId
mysql.mysql(sql, '')
# 更新分片表,文件已合成
sql2 = "UPDATE file_chunks SET fileId = %d WHERE %s" % (fileId, where)
mysql.mysql(sql2, '')
try:
# ExtraArgs={'Metadata': {'Content-Type': 'myvalue'}}
# 修改上传文件元数据Content-Type的类型(不修改Content-Type的类型会默认Content-Type:application/octet-stream,导致访问变成直接下载)
s3.upload_file(fileLocalPath, AWS_BUCKET_NAME, fileS3path, ExtraArgs={'ContentType': fileTypeMime})
fileS3path = parse.quote(fileS3path) # 路径转换
# 删除CDN缓存
response = client.create_invalidation(
# cdn id
DistributionId='E6XIHDDOQNHN',
InvalidationBatch={
'Paths': {
'Quantity': 1,
'Items': [
'/%s' % fileS3path,
]
},
'CallerReference': str(time.time()) # 'string'
}
)
except:
print('上传S3发生了异常')
sql = "UPDATE file SET s3Type = 0 WHERE fileId = %d" % fileId
mysql.mysql(sql, '')
else:
sql = "UPDATE file SET fileS3 = 1, s3Type = 2 WHERE fileId = %d" % fileId
mysql.mysql(sql, '')
print('Success')