您的当前位置:首页>全部文章>文章详情

【PHP】PHP异步协程开发:解决大文件上传与下载的难题

CrazyPanda发表于:2023-12-27 23:25:32浏览:312次TAG:

随着网络技术的发展和应用场景的不断扩展,大文件上传和下载已经成为了许多Web应用面临的难题。传统的处理方式往往耗时较长,效率较低,而PHP异步协程开发则能够有效地解决这些问题。

近年来,PHP语言的异步编程技术逐渐得到了广泛的应用,其中协程技术在实际开发中得到了更广泛的运用。协程是一种用户线程的高级形式,它允许线程中断,等待某些事件的发生,然后再恢复线程的执行。通俗来讲,就是在代码执行过程中,主动让出CPU,进行一些其他的操作。

下面将详细介绍PHP异步协程开发在大文件上传和下载中的应用。

一、大文件上传

在Web应用程序中,大文件上传一般是通过HTTP协议实现的。当用户上传一个大文件时,服务器需要将这个文件读入内存并写入磁盘,这个过程需要耗费大量的时间和资源。如果在传统的处理方式中,一旦上传某个大文件,服务器将会一直等待上传完成,无法同时处理其他请求。这不仅浪费资源,也会影响用户体验。

基于协程的解决方案:

一、客户端将文件分片上传到服务器,这里使用H5的FormData API和XMLHttpRequest对象实现

二、服务器收到上传请求后,检查上传文件的切片数与文件大小是否一致,如果一致,则将收到的切片存入目标文件中。

三、如果不一致,则返回错误信息。如果有任何一个文件块接收失败,应该清理其他已经上传的分块,以免产生半成品文件。

四、上传完成后,服务器端可以对文件属性等进行操作。如果文件比较大,可以异步地对文件进行处理,避免IO与CPU intensive对CPU的敏感度。

下面是一段示例代码:

<?php
// 启用协程运行时
SwooleRuntime::enableCoroutine();
 
$http = new SwooleHttpServer("127.0.0.1", 9501);
 
// 监听HTTP请求
$http->on("request", function ($request, $response) {
 
    // 从请求中获取分块数据
    $chunk = $request->rawContent();
 
    // 获取分块所属的文件名和分块编号
    $fileName = $_POST['fileName'];
    $chunkIndex = $_POST['chunkIndex'];
 
    // 将分块数据追加写入到目标文件中
    $fp = fopen($fileName, 'ab');
    fwrite($fp, $chunk);
    fclose($fp);
 
    // 判断是否上传完成
    if (intval($_POST['totalChunks']) == $chunkIndex + 1) {
        $response->end("Upload completed.");
    } else {
        $response->end("Upload success.");
    }
});
 
$http->start();

二、大文件下载

在Web应用程序中,大文件下载也是通过HTTP协议实现的。当用户需要下载一个大文件时,服务器需要从磁盘中读取文件并将其发送给客户端,这个过程也需要耗费大量的时间和资源。如果在传统的处理方式中,服务器一次性将整个文件读入内存并发送给客户端,这样不仅浪费资源,而且可能导致服务器宕机。

基于协程的解决方案:

一、每次从磁盘中读取一定块的数据,发送给客户端

二、使用协程进行控制,每发送一定量的数据后yield让出CPU

三、当客户端消费完当前的块后,向服务器端发送消息,进入下一个块的数据发送

下面是一段示例代码:

<?php
// 启用协程运行时
SwooleRuntime::enableCoroutine();
 
$server = new SwooleHttpServer('127.0.0.1', 9502);
 
$server->on('request', function($request, $response) {
    $filePath = '/path/to/large/file';
    $startPos = 0;
    $readChunkSize = 8192;
 
    $fileSize = filesize($filePath);
 
    $response->header('Content-Type', 'application/octet-stream');
    $response->header('Accept-Ranges', 'bytes');
 
    // 读取和发送一块数据
    function readAndSendChunk($fp, $response, $startPos, $readChunkSize, $fileSize) {
        fseek($fp, $startPos);
        $maxLength = $fileSize - $startPos;
        if ($maxLength > $readChunkSize) {
            $maxLength = $readChunkSize;
        }
        $data = fread($fp, $maxLength);
        $response->write($data);
        return $startPos + $maxLength;
    }
 
    // 每发送一定量的数据后yield,让出CPU
    function sendByYield($fp, $response, $startPos, $readChunkSize, $fileSize) {
        while ($startPos < $fileSize) {
            $startPos = readAndSendChunk($fp, $response, $startPos, $readChunkSize, $fileSize);
            yield;
        }
        fclose($fp);
        $response->end();
    }
 
    // 检查是否支持断点续传
    $range = $request->header['range'];
    if ($range) {
        $status = '206 Partial Content';
        $range = explode('-', substr($range, 6));
        if ($range[0] === '') {
            $startPos = $fileSize - intval($range[1]);
        } else if ($range[1] === '') {
            $startPos = intval($range[0]);
        } else {
            $startPos = intval($range[0]);
            $readChunkSize = intval($range[1]) - $startPos + 1;
            $response->header('Content-Length', $readChunkSize);
        }
    } else {
        $status = '200 OK';
        $response->header('Content-Length', $fileSize);
    }
 
    $response->header('HTTP/1.1', $status);
    $response->header('Content-Disposition', 'attachment;filename="'.basename($filePath).'"');
    $response->header('Content-Range', 'bytes '.$startPos.'-'.($startPos+$readChunkSize-1).'/'.$fileSize);
 
    $fp = fopen($filePath, 'rb');
    fseek($fp, $startPos);
 
    $response->status(200);
 
    // 使用协程进行控制
    for ($i = 1; $i <= 5; $i++) {
        go(function() use ($fp, $response, $startPos, $readChunkSize, $fileSize) {
            yield from sendByYield($fp, $response, $startPos, $readChunkSize, $fileSize);
        });
    }
});
 
$server->start();

结语:

本文详细介绍了PHP异步协程开发在大文件上传和下载中的应用,并给出了具体的代码实现示例。在实际开发中,使用基于协程的异步编程技术,能够有效地提高Web应用的处理性能和用户体验,值得开发者深入研究和探索。

以上就是PHP异步协程开发:解决大文件上传与下载的难题的详细内容,更多请关注php中文网其它相关文章!

猜你喜欢

【PHP】ThinkPHP如何防止SQL注入攻击
在ThinkPHP中,参数绑定是一种安全的方式,用于处理用户输入,特别是在构建数据库查询时。参数绑定可以防止SQL注入攻击,因为绑定的参数会被自动转义,而不是直接插入到SQL语句中。以下是在ThinkPHP中使用参数绑定的一些建议。1. 控制器中的参数绑定:在控制器中,可以使用bind方法进行参数绑定。以下是一个简单的示例:public&nbsp;function&nbsp;index($id) { &nbsp;&nbsp;&nbsp;&nbsp;$result&nbsp;=&nbsp;Db::
发表于:2024-01-04 浏览:325 TAG:
【PHP】json去除多余空格 php
随着互联网技术的不断发展,前后端交互的过程中通讯协议也逐渐从XML格式转变为JSON格式。在使用JSON格式时,发现有时候会出现多余的空格,这些空格不仅会增加数据传输的负担,而且在解析JSON数据时还会出现问题。因此,在实际开发中,我们需要把JSON数据中的多余空格去掉。本文将介绍如何通过PHP去除JSON数据中多余空格。一、多余空格产生的原因在理解如何去掉JSON中的多余空格之前,我们先来了解一下多余空格的产生原因。数据格式不规范一些程序员在编写代码时,可能会本着“小问题不是问题”的
发表于:2023-12-20 浏览:328 TAG:
【PHP】CI,ThinkPHP,YII,Laravel框架比较
用过其中的yii TP CI框架。大概整理了这些框架的优点和缺点,有些错误的地方还希望大家指正。各个框架各有所长,针对的应用场景不同。一、Ci框架推崇简单就是美这一原则,没有花哨的设计模式,没有华丽的对象结构,一切就是那么简单。优点:框架的入门槛很低,极易学,极易用,框架很小,静态化非常容易配置简单,全部的配置使用php脚本来配置,执行效率高缺点:架构略简单,只能满足小型应用,略微不太能够满足中型应用需要大型项目扩展能力差,有些功能需要自己写扩展数据库类的扩展 ci给用户提供了一个名为call_
发表于:2024-07-14 浏览:303 TAG: #php #框架
【PHP】PHP协程(Coroutine)
协程(Coroutine)是一种用户态的轻量级线程,它的执行可以被挂起(暂停),之后可以从挂起点恢复执行。与线程不同,协程的切换不需要内核的参与,完全在用户态进行,因此切换的代价非常小。这使得协程非常适合用于处理大量的并发任务,尤其是I/O密集型任务。
发表于:2024-12-30 浏览:159 TAG: #php #swoole #协程
【PHP】php数组合并有几种方法
php数组合并有四种方法。详细介绍:1、使用array_merge()函数,接受多个数组作为参数,并返回一个合并后的数组;2、使用&quot;+&quot;运算符,将两个数组合并为一个新数组,并返回结果;3、使用array_merge_recursive()函数,用于合并两个或多个数组,并且可以处理多维数组的合并;4、使用array_replace()函数等等。本教程操作环境:windows10系统、php8.1.3版本、DELL G3电脑。在PHP中,数组合并是一种常见的操作,它可以
发表于:2023-12-06 浏览:391 TAG:
【PHP】PHP新潮流:教你如何用Symfony Panther库构建强大的爬虫,顺利获取TikTok网站的数据
引入你是否想过用PHP来编写爬虫,从网上抓取你感兴趣的数据?你是否觉得PHP的爬虫库太少,功能太弱,无法满足你的需求?你是否曾经遇到过动态网页,需要模拟浏览器的行为,才能获取到你想要的数据?如果你的答案是肯定的,那么你一定要了解一下Symfony Panther这个PHP库。Symfony Panther是一个基于Symfony框架的爬虫库,它可以让你用PHP轻松地创建和运行强大的爬虫,甚至可以处理复杂的动态网页,比如TikTok这样的热门社交媒体网站。在这篇文章中,我将向你介绍Symfony
发表于:2024-01-04 浏览:317 TAG:
【PHP】设计模式的六大原则
设计模式的六大原则是指导软件开发设计的核心原则,它们帮助开发人员创建可维护、可扩展和灵活的软件系统。这些原则包括:&nbsp;‌&nbsp;&nbsp;&nbsp;&nbsp;单一职责原则(Single Responsibility Principle, SRP):一个类应该只有一个引起它变化的原因。这有助于减少类与类之间的耦合,提高类的内聚性和可读性。&nbsp;‌&nbsp;&nbsp;&nbsp;&nbsp;开闭原则(Open-Closed Principle, OCP):软件实体(如类、
发表于:2024-07-16 浏览:271 TAG:
【PHP】TP上传图片到OSS
准备:php版本:7.4tp版本:6.0阿里云accessKeyId;阿里云accessKeySecret;阿里云存储bucket名称,如&nbsp;examplebucket;地域节点endpoint,如:oss-cn-hangzhou.aliyuncs.com;1. 安装SDK参考官网https://help.aliyun.com/zh/oss/developer-reference/installation-13?spm=a2c4g.11186623.0.0.568f6583XllxTu
发表于:2024-03-23 浏览:393 TAG:
【PHP】制作自己的Composer插件并与其他开发者共享
如何编写自己的Composer插件并分享给其他开发者在现代的PHP开发领域,Composer已经成为了一个不可或缺的工具。它可以帮助开发者管理项目依赖和自动加载类,大大简化了项目的构建过程。除了使用Composer来安装第三方的扩展包之外,我们也可以使用Composer来编写自己的插件,并将其分享给其他开发者。本文将逐步介绍如何编写自己的Composer插件,并提供具体的代码示例。首先,我们需要创建一个空的Composer插件项目。在命令行中进入项目根目录,然后执行以下命令:compo
发表于:2023-12-27 浏览:341 TAG:
【PHP】php怎么去数组中的指定几条
php使用下标、array_key_exists()函数、isset()函数、unset()函数和array_splice()函数去数组中的指定几条。详细介绍:1、下标,下标从0开始,依次递增;2、array_key_exists()函数,该函数接受两个参数,第一个参数是要检查的键,第二个参数是要检查的数组;3、isset()函数,接受一个参数,即要检查的数组元素等等。本教程操作环境:windows10系统、php8.1.3版本、DELL G3电脑。PHP是一种广泛使用的编程语言,它提
发表于:2023-12-06 浏览:298 TAG: