使用php方法传递参数执行python程序实现大文件合并分片文件并上传AWS S3

7 篇文章 2 订阅

 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')

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值