>백엔드 개발 >PHP 튜토리얼 >PHP에서 예약된 작업을 실행하기 위한 여러 가지 방법과 아이디어

PHP에서 예약된 작업을 실행하기 위한 여러 가지 방법과 아이디어

小云云
小云云원래의
2018-03-14 14:07:183910검색

PHP 자체에는 타이밍 기능이 없으며 PHP는 멀티스레드가 불가능합니다. 이를 달성하려면 PHP의 예약된 작업 기능을 다른 도구와 결합해야 합니다. 예를 들어 WordPress에는 매우 강력한 wp-cron 기능이 내장되어 있습니다. 이 기사에서는 몇 가지 일반적인 PHP 예약 작업에 대한 아이디어를 심층적으로 분석합니다.

1. CronTab을 사용하여 Linux 서버에서 정기적으로 PHP를 실행합니다.

비교적 복잡한 PHP 서버 실행부터 시작해 보겠습니다. 서버에 PHP를 설치하면 nginx, Apache 등 서버 환경 소프트웨어 설치 여부에 관계없이 PHP 파일을 실행할 수 있습니다. Linux에서는 명령줄과 CronTab을 사용하여 작업을 예약하는 것이 탁월한 선택이자 가장 효율적인 선택입니다.

먼저 명령줄 모드로 들어갑니다. 서버로서 Linux는 일반적으로 기본적으로 명령줄 모드로 들어갑니다. 물론 우리 관리 서버도 일반적으로 편의상 putty와 같은 도구를 통해 원격으로 서버에 연결합니다. 명령줄에

crontab -e

를 입력하면 파일이 열리고 편집되지 않는 상태가 됩니다. 키보드에서 i를 눌러 편집 모드로 들어가면 편집할 수 있습니다. 내용. 이 파일의 각 줄은 예약된 작업입니다. 새 줄을 만들면 새 예약된 작업이 생성됩니다(물론 이는 이 줄에 특정 형식으로 쓰는 것을 의미합니다). 이제 예를 들어 다음 내용이 포함된 줄을 추가해 보겠습니다.

00 * * * * lynx -dump https://www.yourdomain.com/script.php

이게 무슨 뜻인가요? 실제로 위의 줄은 두 부분으로 구성되어 있는데, 첫 번째 부분은 시간이고, 뒷부분은 작업 내용입니다. 예를 들어 위의 예에서

00 * * * *

는 현재 시간의 분이 00일 때 예약된 작업이 실행된다는 의미입니다. 시간 부분은 다음과 같은 5개의 시간 매개변수로 구성됩니다.

分 时 日 月 周
第1列表示分钟1~59 每分钟用或者 */1表示,/n表示每n分钟,例如*/8就是每8分钟的意思,下面也是类推
第2列表示小时1~23(0表示0点)
第3列表示日期1~31第4列表示月份1~12第5列标识号星期0~6(0表示星期天)

전체 문장의 후반 부분은 작업의 구체적인 내용입니다.

lynx -dump https://www.yourdomain.com/script.php

Lynx를 통해 이 URL에 액세스한다는 의미입니다. 우리는 URL에 대한 원격 액세스를 위해 주로 lynx, 컬 및 wget을 사용합니다. 효율성을 높이려면 PHP를 사용하여 로컬 PHP 파일을 직접 실행하는 것이 가장 좋습니다. 예:

00 */2 * * * /usr/local/bin/php /home/www/script.php

이 명령문은 Every 2에서 사용할 수 있습니다. 1시간 0분이면 Linux 내부 PHP 환경을 통해 script.php가 실행되는데, 이는 URL을 통해 접속하지 않고 서버 환경을 통해 직접 실행되기 때문에 효율성은 당연히 높다. .

알겠습니다. 몇 가지 필수 예약 작업이 추가되었습니다. 키보드의 Esc 키를 클릭하고 ":wq"를 입력한 후 Enter를 누르세요. 이렇게 하면 설정된 예약 작업이 저장되고 화면에 새 예약 작업이 생성되었다는 메시지도 표시됩니다. 다음 단계는 script.php를 올바르게 작성하는 것입니다.

여기에서는 CronTab의 사용법을 더 소개하지 않겠습니다. 이 예약된 작업 기능을 보다 유연하게 사용하려면 crontab에 대해 직접 배워야 합니다.

2. Windows 서버에서 정기적으로 PHP를 실행하려면 bat을 사용하세요.

Windows와 Linux에는 유사한 cmd 및 bat 파일이 있습니다. bat 파일은 셸 파일을 실행하는 것과 같습니다. 시퀀스(물론 프로그래밍은 논리를 통해 구현될 수도 있음)이므로 bat 명령 파일을 사용하여 Windows 서버에서 PHP 예약 작업을 구현할 수 있습니다. 실제로 Windows에서 예약된 작업의 원리는 Linux와 동일하지만 방법과 접근 방식이 다릅니다. 좋아요, 시작해 보겠습니다.

먼저, 더 적절하다고 생각되는 위치에 cron.bat 파일을 만든 다음 텍스트 편집기로 열고(메모장이 작동함) 다음 내용을 작성합니다.

D:\php\php.exe -q D:\website\test.php

이 문장은 , php 사용을 의미합니다. .exe를 사용하여 php 파일 test.php를 실행합니다. 위의 contab과 마찬가지로 서버 환경을 우회하여 실행 효율성이 상대적으로 높습니다. 작성 후 저장을 클릭하고 편집기를 닫습니다.

다음 단계는 cron.bat를 실행하도록 예약된 작업을 설정하는 것입니다. 순서대로 엽니다: "시작 -> 제어판 -> 작업 일정 -> 작업 일정 추가", 열린 인터페이스에서 예약된 작업의 시간과 비밀번호를 설정하고 cron.bat를 선택하여 마운트합니다. 자, 예약된 작업이 생성되었습니다. 예약된 작업을 마우스 오른쪽 버튼으로 클릭하고 실행하면 예약된 작업이 실행되기 시작합니다. 시간이 지나면 cron.bat가 실행되어 처리됩니다. PHP를 실행합니다.

3. 소유하지 않은 서버(가상 호스트)에서 PHP 예약 작업 구현

웹마스터가 자체 서버가 없고 가상 호스트를 임대하는 경우 서버 시스템에 들어가 위 작업을 수행할 수 없습니다. 현재 PHP 예약 작업을 어떻게 수행해야 합니까? 사실 방법은 여러 가지가 있습니다.

4.ignore_user_abort(true) 및 sleep 무한 루프 사용

PHP 문서 시작 부분에 직접 문장을 말하세요:

ignore_user_abort(true);

이때 URL을 통해 이 PHP에 액세스할 때 사용자가 브라우저를 닫더라도( 연결을 끊습니다)), PHP는 서버에서 계속 실행됩니다. 이 기능을 사용하면 예약된 작업을 활성화하는 데 사용할 수 있는 매우 강력한 기능을 얻을 수 있습니다. 활성화 후에는 실제로 백그라운드 작업과 다소 유사합니다.

그리고 sleep(n)은 여기서 프로그램이 실행될 때 일시적으로 실행을 계속하지 않고 n초 동안 쉬는 것을 의미합니다. 이 PHP에 액세스하면 페이지를 로드하는 데 최소 n초가 걸리는 것을 알 수 있습니다. 실제로 이러한 장기 대기 동작은 리소스를 소모하므로 대량으로 사용할 수 없습니다.

那么定时任务到底怎么实现呢?使用下面的代码即可实现:

<?php

ignore_user_abort(true);
set_time_limit(0);
date_default_timezone_set(&#39;PRC&#39;); // 切换到中国的时间$run_time = strtotime(&#39;+1 day&#39;); // 定时任务第一次执行的时间是明天的这个时候$interval = 3600*12; // 每12个小时执行一次if(!file_exists(dirname(__FILE__).&#39;/cron-run&#39;)) exit(); // 在目录下存放一个cron-run文件,如果这个文件不存在,说明已经在执行过程中了,该任务就不能再激活,执行第二次,否则这个文件被多次访问的话,服务器就要崩溃掉了do {  if(!file_exists(dirname(__FILE__).&#39;/cron-switch&#39;)) break; // 如果不存在cron-switch这个文件,就停止执行,这是一个开关的作用  $gmt_time = microtime(true); // 当前的运行时间,精确到0.0001秒  $loop = isset($loop) && $loop ? $loop : $run_time - $gmt_time; // 这里处理是为了确定还要等多久才开始第一次执行任务,$loop就是要等多久才执行的时间间隔  $loop = $loop > 0 ? $loop : 0;  if(!$loop) break; // 如果循环的间隔为零,则停止
  sleep($loop); 
  // ...  // 执行某些代码  // ...
  @unlink(dirname(__FILE__).&#39;/cron-run&#39;); // 这里就是通过删除cron-run来告诉程序,这个定时任务已经在执行过程中,不能再执行一个新的同样的任务  $loop = $interval;
} while(true);

通过执行上面这段php代码,即可实现定时任务,直到你删除cron-switch文件,这个任务才会停止。

但是有一个问题,也就是如果用户直接访问这个php,实际上没有任何作用,页面也会停在这个地方,一直处于加载状态,有没有一种办法可以消除这种影响呢?fsockopen帮我们解决了这个问题。

fsockopen可以实现在请求访问某个文件时,不必获得返回结果就继续往下执行程序,这是和curl通常用法不一样的地方,我们在使用curl访问网页时,一定要等curl加载完网页后,才会执行curl后面的代码,虽然实际上curl也可以实现“非阻塞式”的请求,但是比fsockopen复杂的多,所以我们优先选择fsockopen,fsockopen可以在规定的时间内,比如1秒钟以内,完成对访问路径发出请求,完成之后就不管这个路径是否返回内容了,它的任务就到这里结束,可以继续往下执行程序了。利用这个特性,我们在正常的程序流中加入fsockopen,对上面我们创建的这个定时任务php的地址发出请求,即可让定时任务在后台执行。如果上面这个php的url地址是www.yourdomain.com/script.php,那么我们在编程中,可以这样:

// ...// 正常的php执行程序// ..// 远程请求(不获取内容)函数,下面可以反复使用function _sock($url) {
  $host = parse_url($url,PHP_URL_HOST);
  $port = parse_url($url,PHP_URL_PORT);
  $port = $port ? $port : 80;
  $scheme = parse_url($url,PHP_URL_SCHEME);
  $path = parse_url($url,PHP_URL_PATH);
  $query = parse_url($url,PHP_URL_QUERY);  if($query) $path .= &#39;?&#39;.$query;  if($scheme == &#39;https&#39;) {
    $host = &#39;ssl://&#39;.$host;
  }

  $fp = fsockopen($host,$port,$error_code,$error_msg,1);  if(!$fp) {    return array(&#39;error_code&#39; => $error_code,&#39;error_msg&#39; => $error_msg);
  }  else {
    stream_set_blocking($fp,true);//开启了手册上说的非阻塞模式
    stream_set_timeout($fp,1);//设置超时
    $header = "GET $path HTTP/1.1\r\n";
    $header.="Host: $host\r\n";
    $header.="Connection: close\r\n\r\n";//长连接关闭
    fwrite($fp, $header);
    usleep(1000); // 这一句也是关键,如果没有这延时,可能在nginx服务器上就无法执行成功
    fclose($fp);    return array(&#39;error_code&#39; => 0);
  }
}

_sock(&#39;www.yourdomain.com/script.php&#39;);// ...// 继续执行其他动作// ..

把这段代码加入到某个定时任务提交结果程序中,在设置好时间后,提交,然后执行上面这个代码,就可以激活该定时任务,而且对于提交的这个用户而言,没有任何页面上的堵塞感。

5、借用用户的访问行为来执行某些延迟任务

但是上面使用sleep来实现定时任务,是效率很低的一种方案。我们希望不要使用这种方式来执行,这样的话就可以解决效率问题。我们借用用户访问行为来执行任务。用户对网站的访问其实是一个非常丰富的行为资源,包括搜索引擎蜘蛛对网站的访问,都可以算作这个类型。在用户访问网站时,内部加一个动作,去检查任务列表中是否存在没有被执行的任务,如果存在,就将这个任务执行。对于用户而言,利用上面所说的fsockopen,根本感觉不到自己的访问竟然还做出了这样的贡献。但是这种访问的缺点就是访问很不规律,比如你希望在凌晨2点执行某项任务,但是这个时间段非常倒霉,没有用户或任何行为到达你的网站,直到早上6点才有一个新访问。这就导致你原本打算2点执行的任务,到6点才被执行。

这里涉及到一个定时任务列表,也就是说你需要有一个列表来记录所有任务的时间、执行什么内容。一般来说,很多系统会采用数据库来记录这些任务列表,比如wordpress就是这样做的。我则利用文件读写特性,提供了托管在github上的开源项目php-cron,你可以去看看。总之,如果你想要管理多个定时任务,靠上面的单个php是无法合理布局的,必须想办法构建一个schedules列表。由于这里面的逻辑比较复杂,就不再详细阐述,我们仅停留在思路层面上。

6、借用第三方定时任务跳板

很好玩的是,一些服务商提供了各种类型的定时任务,例如阿里云的ACE提供了单独的定时任务,你可以填写自己应用下的某个uri。百度云BCE提供了服务器监测功能,每天会按照一定的时间规律访问应用下的固定uri。类似的第三方平台上还有很多定时任务可以用。你完全可以用这些第三方定时任务作为跳板,为你的网站定时任务服务。比如说,你可以在阿里云ACE上建立一个每天凌晨2点的定时任务,执行的uri是/cron.php。然后你创建一个cron.php,里面则采用fsockopen去访问你真正要执行某些任务的网站的url,例如上面的www.yourdomain.com/script.php,而且在cron.php中还可以访问多个url。然后把cron.php上传到你的ACE上面去,让ACE的定时任务去访问/cron.php,然后让cron.php去远程请求目标网站的定时任务脚本。

7、循环利用include包含文件(待验证)

php面向过程的特性使得其程序是从上往下执行的,利用这个特性,在我们使用include某个文件时,就会执行被引入的文件,知道include的文件内程序执行完之后,再往下执行。如果我们创建一个循环,再利用sleep,不断的include某个文件,使循环执行某段程序,则可以达到定时执行的目的。我们再进一步,并不是利用while(true)来实现循环,而是利用被include文件本身再include自身来实现循环,比如我们创建一个do.php,它的内容如下:

if(...) exit(); // 通过某个开关来关闭执行// ... 
// 执行某些程序// ...

sleep($loop); // 这个$loop在include(&#39;do.php&#39;);之前赋值

include(dirname(__FILE__).&#39;/do.php&#39;);

其实通过这种方法执行和while的思路也像。而且同样用到sleep,效率低。

PHP 예약 작업은 매우 흥미로운 일입니다. 솔직히 말해서 시스템의 php.exe를 사용하여 PHP 파일을 직접 실행하는 것이 더 효율적이지만 많은 일반 웹마스터의 경우 가상 호스트는 기본 PHP 파일을 직접 실행할 수 없습니다. 이 글은 단지 몇 가지 해결 방법을 제시하는 것 뿐인데, 질문이나 잘못된 표현이 많으니 지적해 주시길 바랍니다. 나와 함께 논의해 보세요.

관련 권장 사항:

예약 작업의 PHP 구현에 대한 자세한 설명

예약 작업의 PHP 구현에 대한 자세한 설명_PHP

예약 작업의 PHP 구현에 대한 자세한 설명_php 기술

위 내용은 PHP에서 예약된 작업을 실행하기 위한 여러 가지 방법과 아이디어의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.