分类 PHP 下的文章

  1. 前端页面将文件分块上传。
  2. 后端在最后一条时进行合并处理。
  3. 最后一条需要等待前面的上传完毕再执行,因此用Promise.all() 函数处理。

前端js

    function getRandChars(e) {
        e = e || 32;
        var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
            a = t.length,
            n = "";
        for (i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a));
        return n
    }

    function uploadFile(url, blob, callback) {
        var perFileSize = 2097152; // 2 * 1024 * 1024
        var blobParts = Math.ceil(blob.size / perFileSize);
        const fileName = getRandChars();
        layer.msg("文件上传中", {
            icon: 16,
            time: -1
        })
        function request(url, fd, callback) {
            return new Promise((resolve, reject) => {
                $.ajax({
                    type: 'POST',
                    url: url,
                    data: fd,
                    processData: false,
                    contentType: false
                }).done(function (res) {
                    resolve(res);
                }).fail(function (err) {
                    reject(err);
                });
            });
        }
        let beforeRequests = []
        for (var i = 0; i < blobParts; i++) {
            (function (i) {
                var fd = new FormData();
                var _blob = blob.slice(i * perFileSize, (i + 1) * perFileSize);
                fd.append('file', _blob);
                fd.append('fileName', fileName);
                fd.append('index', i + 1);
                fd.append('total', blobParts);
                if (i + 1 < blobParts) {
                    beforeRequests.push(request(url, fd, callback))
                } else {
                    Promise.all(beforeRequests).then(responses => {
                        // 所有请求完成后执行的操作
                        request(url, fd, callback)
                            .then(res => {
                                layer.closeAll()
                                if (res.status == 0) {
                                    layer.msg(res.mes)
                                } else if (res.object.status === 200) {
                                    callback(null, res.object)
                                } else if (res.object.status === 500) {
                                    layer.msg(res.object.msg)
                                }
                            })
                    }).catch(error => {
                        layer.closeAll()
                        callback(error, null)
                    }).finally(() => {
                    });
                }
            })(i)
        }
    }

php 部分

class PartUploadLogic
{
    protected $blobNum;
    protected $totalBlobNum;

    public function UploadInChunks()
    {
        set_time_limit(600);
        ini_set('memory_limit', '3000M');
        $file = $_FILES['file'];
        $this->blobNum = I('index/d', 1);
        $this->totalBlobNum = I('total/d', 1);
        $fileName = I("fileName/s");
        $endPath = '/uploads/file';
        $tmpPath = $endPath . 'tmp/';

        $savePath = date("Ymd");
        $tmpRelativePath = "$tmpPath{$savePath}";
        $tmpSavePath = realpath('') . $tmpRelativePath . "/$fileName";

        if (!is_dir($tmpSavePath)) {
            mkdir($tmpSavePath, 755, true);
        }

        $saveName = $fileName . '_' . $this->blobNum;
        move_uploaded_file($file['tmp_name'], "$tmpSavePath/$saveName");

        // 合并上传的子文件
        if ($this->totalBlobNum == $this->blobNum) {
            if ($this->totalBlobNum > 1) {
                sleep(2);
            }
            try {
                $endRelativePath = "$endPath/$savePath";
                $finishSavePath = realpath('') . $endRelativePath;
                if (!is_dir($finishSavePath)) {
                    mkdir($finishSavePath, 755, true);
                }
                $fp = fopen("{$finishSavePath}/{$fileName}.pdf", "w+");

                // 合并文件
                for ($i = 1; $i <= $this->totalBlobNum; $i++) {
                    $value = "$tmpSavePath/{$fileName}_{$i}";
                    $handle = fopen($value, "rb");
                    if (empty($handle)) {
                        failData('读取不到分包数据');
                    }
                    fwrite($fp, fread($handle, filesize($value)));
                    fclose($handle);
                    unset($handle);
                    @unlink($value);
                }
                del_dir($tmpSavePath);

            } catch (\Exception $exception) {
                return ['status' => 500, 'msg' => "文件合并失败{$exception->getLine()}{$exception->getMessage()}}"];
            }
            return ['status' => 200, 'msg' => 'success', 'path' => "$endRelativePath/{$fileName}.pdf"];
        }
        return ['status' => 201, 'msg' => 'success', 'fileName' => $fileName];
    }
}

由于项目需要,有些内容固定了。

    function sharePNG($id, $avatarPath = '', $name = '', $desc = '')
    {
        if(substr($avatarPath,0,2) == '//'){
            $avatarPath = (\request()->protocol() == 'HTTP/1.1'?'http':'https').":$avatarPath";
        }
        $len = mb_strlen($name);
        if($len > 11){
            $name = mb_substr($name,0,11).'...';
        }
        $path = public_path("/static");
        $path_2 = empty($avatarPath) ? "{$path}fe/avatar.png" : $avatarPath;
        //背景图片对象
        $fromImageInfo = getimagesize($path_2);
        if (!isset($fromImageInfo['bits']) || $fromImageInfo['bits'] >= 1024) {
            $path_2 = "{$path}fe/avatar.png";
        }
        $path_1 = "{$path}fe/share-bg.png";
        $ttf = "{$path}font/weiruanyahei.ttf";
        //创建图片对象
        $image_1 = imagecreatefrompng($path_1);
        $image_2 = radius_img($path_2); // 见 /index.php/archives/146/

        //缩放图片
        // 获取图像信息
        list($bigWidth, $bigHight) = $fromImageInfo;
        //图片缩放,可以根据原图片大小在这里计算等比缩放
        $width = 30;
        $height = 30;
        // 创建缩略图画板
        $newImage = imagecreatetruecolor($width, $height);
        // 启用混色模式
        imagealphablending($newImage, false);
        // 保存PNG alpha通道信息
        imagesavealpha($newImage, true);
        //缩放
        imagecopyresampled($newImage, $image_2, 0, 0, 0, 0, $width, $height, $bigWidth, $bigHight);

        //合成图片
        //imagecopymerge ( resource $dst_im , resource $src_im , int $dst_x , int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h , int $pct )---拷贝并合并图像的一部分
        //将 src_im 图像中坐标从 src_x,src_y 开始,宽度为 src_w,高度为 src_h 的一部分拷贝到 dst_im 图像中坐标为 dst_x 和 dst_y 的位置上。
        //两图像将根据 pct 来决定合并程度,其值范围从 0 到 100。当 pct = 0 时,实际上什么也没做,当为 100 时对于调色板图像本函数和 imagecopy() 完全一样,它对真彩色图像实现了 alpha 透明。
        imagecopymerge($image_1, $newImage, 10, 125, 0, 0, imagesx($newImage), imagesy($newImage), 100);
        $col = imagecolorallocatealpha($image_1, 0, 0, 0, 0);
        // 设置文字
        imagettftext($image_1, 10, 0, 47, 138, $col, $ttf, $name);
        $col2 = imagecolorallocatealpha($image_1, 171, 171, 171, 0);
        imagettftext($image_1, 8, 0, 47, 153, $col2, $ttf, $desc);
        if (!is_dir("{$path}/sharePNG")) {
            mkdir("{$path}/sharePNG", 755);
        }
        $fullPath = "{$path}/sharePNG/$id.png";
        if (file_exists($fullPath)) {
            unlink($fullPath);
        }
        if (imagepng($image_1, $fullPath)) {
            return "/static/sharePNG/$id.png";
        }
        return false;
    }

参考:

PHP缩放并合成图片
php 合成图片、合成圆形图片

话不多说上代码

function radius_img($imgpath, $radius = 0){
    $index = strpos($imgpath,"?");
    if($index !== false){
        $imgpath = substr($imgpath,0,$index);
    }
    $ext = pathinfo($imgpath);
    $src_img = null;
    switch ($ext['extension']){
        case 'jpg':
        case 'jpeg':
            $src_img = imagecreatefromjpeg($imgpath);
            break;
        case 'png':
            $src_img = imagecreatefrompng($imgpath);
            break;
        case 'gif':
            $src_img = imagecreatefromgif($imgpath);
            break;
    }
    $wh = getimagesize($imgpath);
    $w = $wh[0];
    $h = $wh[1];
    $radius = $radius == 0 ? (min($w, $h) / 2) : $radius;
    $img = imagecreatetruecolor($w, $h);
    //这一句一定要有
    imagesavealpha($img, true);
    //拾取一个完全透明的颜色,最后一个参数127为全透明
    $bg = imagecolorallocatealpha($img, 255, 255, 255, 0);
    imagefill($img, 0, 0, $bg);
    $r = $radius; //圆 角半径
    for ($x = 0; $x < $w; $x++){
        for ($y = 0; $y < $h; $y++){
            $rgbColor = imagecolorat($src_img, $x, $y);
            if (($x >= $radius && $x <= ($w - $radius)) || ($y >= $radius && $y <= ($h - $radius))){
                //不在四角的范围内,直接画
                imagesetpixel($img, $x, $y, $rgbColor);
            }else{
                //在四角的范围内选择画
                //上左
                $y_x = $r; //圆心X坐标
                $y_y = $r; //圆心Y坐标
                if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))){
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
                //上右
                $y_x = $w - $r; //圆心X坐标
                $y_y = $r; //圆心Y坐标
                if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))){
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
                //下左
                $y_x = $r; //圆心X坐标
                $y_y = $h - $r; //圆心Y坐标
                if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))){
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
                //下右
                $y_x = $w - $r; //圆心X坐标
                $y_y = $h - $r; //圆心Y坐标
                if (((($x - $y_x) * ($x - $y_x) + ($y - $y_y) * ($y - $y_y)) <= ($r * $r))){
                    imagesetpixel($img, $x, $y, $rgbColor);
                }
            }
        }
    }
    return $img;
}

装一网站,需要配置php-fpm,我经常开发,却不常运维,很是头大。
当前环境centos7+php7.4+nginx。
安装zip依赖后,需要重启下。

重启方法

master进程可以理解以下信号:

  • INT, TERM 立刻终止
  • QUIT 平滑终止
  • USR1 重新打开日志文件
  • USR2 平滑重载所有worker进程并重新载入配置和二进制模块

方法一

  1. 先查看php-fpm的master进程id:
    ps aux | grep php-fpm | grep master | grep -v grep
  2. 再重启php-fpm:
    kill -USR2 master进程id

方法二

上面master进程可以看到,matster使用的是/usr/local/php/etc/php-fpm.conf(可能有的是/etc/php5/fpm/php-fpm.conf)这个配置文件,cat /usr/local/php/etc/php-fpm.conf看到:

[global]
; Pid file
; Note: the default prefix is /usr/local/php/var
; Default Value: none
;pid = run/php-fpm.pid

pid文件路径应该位于/usr/local/php/var/run/php-fpm.pid,由于注释掉,所以没有生成,我们把注释去除,再kill -USR2 master进程id重启php-fpm,便会生成pid文件,下次就可以使用以下命令重启,关闭php-fpm了:

添加到系统服务

创建文件 php-fpm.service

[Unit]
Description=The PHP FastCGI Process Manager
After=syslog.target network.target
[Service]
Type=simple
PIDFILE=/var/run/php-fpm.pid
ExecStartPre=/usr/bin/rm -f $PIDFILE
ExecStart=/usr/local/php/sbin/php-fpm --nodaemonize --fpm-config /usr/local/php/etc/php-fpm.conf
ExecRestart=/bin/kill -USR2 $PIDFILE
ExecStop=/bin/kill -SIGINT $PIDFILE
[Install]
WantedBy=multi-user.target

复制到这个位置 cp php-fpm.service /etc/systemd/system/php-fpm.service

开机启动

systemctl enable php-fpm.service

Linux改动php.ini后如何重启php-fpm
Centos7下的php-fpm系统服务脚本