Php 在不使用CRON的情况下调度脚本

Php 在不使用CRON的情况下调度脚本,php,scripting,cron,command-line-interface,Php,Scripting,Cron,Command Line Interface,我知道有很多关于使用CRON运行php文件的帖子。但是,在共享主机的世界里,对于用户来说,设置起来很容易,我不想搞砸这件事 我在网上找到了另一个与套接字有关的解决方案。只是想让每个人都接受这个,告诉我这是个好主意还是个坏主意。听起来效果不错 想法 //Open socket connection to cron.php $socketcon = fsockopen($_SERVER['HTTP_HOST'],80,$errorno,$errorstr,10); if($socketcon) {

我知道有很多关于使用CRON运行php文件的帖子。但是,在共享主机的世界里,对于用户来说,设置起来很容易,我不想搞砸这件事

我在网上找到了另一个与套接字有关的解决方案。只是想让每个人都接受这个,告诉我这是个好主意还是个坏主意。听起来效果不错

想法

//Open socket connection to cron.php
$socketcon = fsockopen($_SERVER['HTTP_HOST'],80,$errorno,$errorstr,10);
if($socketcon) {
$socketdata = "GET /cron.php HTTP 1.1\r\nHost: ".$_SERVER['HTTP_HOST']."\r\nConnection: Close\r\n\r\n";
fwrite($socketcon,$socketdata);
//Normally you would get all the data back with fgets and wait until $socketcon reaches feof.
//In this case, we just do this:
fclose($socketcon);
} else {
//something went wrong. Put your error handler here.
}
cron.php:

//This script does all the work.
sleep(200);
//To prove that this works we will create an empty file here, after the sleep is done.
//Make sure that the webserver can write in the directory you're testing this file in.
$handle = fopen('test.txt','w');
fclose($handle);

从博客帖子中找到脚本:

这不是一个坏方法,但您需要确保关闭套接字不仅仅是在脚本完成之前终止脚本。您可以将套接字设置为非阻塞


我仍然会使用cron作业,即使有点痛苦。

cron作业基本上就是cron作业。您设置了它,操作系统会为您运行作业。我不确定您从该站点获得的PHP脚本是如何工作的,但是如果它需要人工干预,那么它就不是真正的cron作业。如果不想使用cron,可以使用循环,然后使用PHP的date函数设置日期和时间。伪码

while (1) {
    $d=date("d");
    if ( $d == "01" ){
        //run every 1st of month
        //code to run here
    }
}

如果我理解的很好,您将从远程机器运行第一个脚本,并在第二个脚本上运行,该脚本将托管在禁用cron的主机上?那么,当您立即关闭连接时,由于php/webserver交互的错误或奇怪特性,脚本不会超时吗

第一部分是相当普遍的做法,甚至有公司提供这项服务(例如,在您要求的任何时候,会自动戳出您想要的任何脚本,并收取费用)


第二部分我不知道。在我看来,这似乎是php/webserver交互中的一个bug,但我可能错了。无论如何,我会再次检查它是否是一个bug(等等,这就是你现在正在做的事吧?),如果它被证明是合法的行为,那么就去做吧。如果它似乎是一个bug,那么不要依赖它,因为它随时都可能被修复。

这是一个功能强大但奇怪的解决方案,可以确保您需要让您的机器在运行第一个脚本的一整天都处于连接状态。如果您想这样做,我建议您使用一个shell脚本,使用wget或curl

例如:

#!/bin/sh

curl -O http://www.myserver.com/cron.php 2>&1 > /var/log/remote.cron.log

但我认为,如果您不必非常同步地运行,您希望实现的解决方案是在index.php的末尾进行检查,查看它上次运行脚本的时间,如果是在两个多小时前,那么
include('cron.php')
。您还可以将脚本运行时的时间戳存储在环境变量中,以避免性能损失

据我从那篇博客文章和代码中了解,这并不是一种不允许cron访问的方法,而是一种避免有人等待服务器响应长查询的方法。如果您必须执行某个脚本,比如说每10分钟左右执行一次,那么您需要使用cron。如果您只是想避免让用户等待很长的查询完成,那么这种黑客可能会奏效。即使使用这种方法,我仍然认为如果您的脚本花费的时间超过PHP允许完成的时间,您将达到时间限制

回顾wp cron.php(在博客链接中提到),它看起来完全依赖于访问站点的用户触发对时间戳作业集的检查


除非您有另一台服务器以特定的时间间隔ping,否则这些技术不会非常可靠。该技术的主要目标是避免用户每隔一段时间等待清理或维护脚本运行15秒,而不是真正替代cron的所有用途。

这会产生与cron不同的效果

cron作业在您提前设置的特定时间内运行

您的方法基本上是一种对PHP脚本的“fork”或“异步调用”。像在这里一样通过HTTP进行操作是一种既便宜又简单的技术。我自己用。它与cron的不同之处在于它立即启动“后台进程”

不过有几点评论:

  • 首先,您应该在“后台”脚本中调用
    ignore\u user\u abort()
    。否则,在许多环境中,当“调用”脚本关闭套接字时,脚本将中止

  • 其次,您可以在“后台”脚本中实际检查
    $\u SERVER['HOST']
    变量,这样您就可以拥有不暴露于internet的脚本(基本上是向
    localhost
    发出请求并在后台脚本中检查)。然后,您可以假定信任来自您自己机器的请求,并跳过所有安全检查、会话等

  • 第三,谁说“后台”脚本必须使用PHP运行?如果要将PHP用作“后台”进程,它有很多弱点。主要的缺点是它会阻塞I/O。因此,如果要发送电子邮件、更新数据库行或其他任何内容,基本上每次发送请求时都会暂停脚本。而对于Node.js,您可以异步启动I/O命令并继续运行。如果您打算使用PHP,至少要确保一次发送10封电子邮件,或者一次更新10行,或者其他什么

  • 最后,如果背景脚本正在执行某些操作,您可能希望在浏览器上显示进度条。因此,您需要使用公共数据存储(如数据库)来记录任务的进度


  • 我花了好几天时间才找到一个有效的解决方案,而没有竞争条件和/或淹没我自己的服务器,但最后我认为这应该是可行的:

    我假设如果您依赖于共享机器,您将无法维持php脚本的运行。即使机器重新启动,这个解决方案也会继续工作。@Bill Karwin-因为轮子实际上是方形的。:)或者只使用
    time\u sleep\u till()
    忽略用户\u abort
    绝对是模拟rea的关键