用的是虚拟主机,没有SSH权限,所以用不了crontab,请问PHP如何实时类似crontab定时任务。

2010-12-25 19:22:39

3 Answers

如果可以使用 cli 模式的话,那么完全可以使用 php xx.php 的形式来执行计划任务,使用set_time_limit方法来限定时间,如果需要跑多个实例,可以使用文件锁的形式来确保;

如果是web形式的话,则可以使用js来配合,像wp里面的cron其实就是这么实现的...

之前在团购平台上实现了一个这样的应用,此处我给出一些代码:

/**
* 任务计划类 taskschedule
* 
* 读取指定的 任务配置文件 来执行任务计划
*/
class TaskSchedule {
    
    /**
     * 运行时目录,存放 锁定文件 和 日志文件 所在地
     *
     * @var string
     */
    static $rtDir = null;
    
    /**
     * 锁定文件标识,确保单台机器内存中只有一个运行实例
     */
    const LOCK_PID = 'taskschedule.pid';
    
    private function __construct(){
        // 此处可以扩展成 读取配置文件 
        $this->_tasks = require 'tasks.php';
    }
    
    /**
     * 返回 TaskSchedule 单例对象
     * 
     * @return TaskSchedule
     */
    static function getInstance(){
        static $inst = null;
        if (!$inst)
            $inst = new self();     
        return $inst;
    }
    
    /**
     * 运行 任务实例
     */
    function dealTask($id){
        
        if (isset($this->_tasks[$id])){
            $inst = isset($this->_tasks[$id]['inst']) ? $this->_tasks[$id]['inst'] : null;
                        
            if ($inst instanceof TaskBase){
                // Only a instance can execute
            }else {
                $className = $this->_tasks[$id]['class'];
                
                if (!class_exists($className,false)){
                    require_once $this->_tasks[$id]['file'];
                }
                
                if (isset($this->_tasks[$id]['config']))
                    $inst = new $className($this->_tasks[$id]['config']);
                else
                    $inst = new $className();
                    
                $this->_tasks[$id]['inst'] = $inst;
                
                $inst->run();
            }
            
        }else {
            CoreApp::writeLog("task: {$id} not defined ",'error');
        }
    }
}

class TaskScheduleException extends Exception {}

abstract class TaskBase {
    
    /**
     * 任务标题
     *
     * @var string
     */
    public $title;
    
    /**
     * 起始时间
     *
     * @var int
     */
    public $st;
    
    /**
     * 结束时间
     *
     * @var int
     */
    public $et;
    
    /**
     * 执行任务,由任务制定者实现
     */
    abstract function run();
    
}
		
调用的时候 ignore_user_abort(); $op = "你定义的标识" TaskSchedule::getInstance()->dealTask($op);
2010-12-25 21:33:04

有几个方法:
1.使用ignore_user_abort(true)来设置当用户请求中断后,继续执行脚本。discuz里面有一个使用ignore_user_abort实现的cron类,可以拿来参考一下。

2.如果有fsockopen权限,可以使用fsockopen("127.0.0.1", 80, $errno, $errstr, 30);来让服务器脚本请求自己的脚本:

$fp = fsockopen("127.0.0.1", 80, $errno, $errstr, 30); if($fp){ $out = "GET /?act=XXXX HTTP/1.1\r\n"; $out .= "Host: ".$_SERVER['HTTP_HOST']."\r\n"; $out .= "Cookie:PHPSESSID=xxxxxx\r\n"; $out .= "Connection: Close\r\n\r\n"; fputs($fp, $out); }

上面的代码让其反复请求一个接口就行,这个要注意拿一个数据库来标示cron是否在运行中

3.如果PHP是用fastcgi方式运行的,可以用fastcgi_finish_request()函数提前终止HTTP请求,然后后面用循环+sleep实现cron的功能。

2010-12-25 22:36:18

php文档中有这样的例子:

If you want to simulate a crontask you must call this script once and it will keep running forever (during server uptime) in the background while "doing something" every specified seconds (= $interval): <?php ignore_user_abort(1); // run script in background set_time_limit(0); // run script forever $interval=60*15; // do every 15 minutes... do{ // add the script that has to be ran every 15 minutes here // ... sleep($interval); // wait 15 minutes }while(true); ?>

我感觉这不是最好的解决方法。。。

其实有一些变通的方法,比如 在一个有SSH权限的主机上定时请求 你的虚拟主机,你必须先给这个主机一个请求的接口 

文档地址:http://cn.php.net/manual/zh/function.ignore-user-abort.php

2010-12-26 00:32:46
您不能回答该问题或者回答已经关闭!

相关文章推荐

  • C#开发中的反射机制

    反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等

  • C#实例解析适配器设计模式

    将一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够一起工作

  • C#中using指令的几种用法

    using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到

  • C#协变和逆变

    “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型,“逆变”则是指能够使用派生程度更小的类型

  • C#运行时相互关系

    C#运行时相互关系,包括运行时类型、对象、线程栈和托管堆之间的相互关系,静态方法、实例方法和虚方法的区别等等

  • 使用托管C++粘合C#和C++代码(二)

    本文实现一下C++代码调用C#代码的过程。我构造一个简单并且直观的例子:通过C++ UI 触发C# UI.

  • C#开发高性能Log Help类设计开发

    项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多

  • C#中的索引器的简单理解和用法

    C#中的类成员可以是任意类型,包括数组和集合。当一个类包含了数组和集合成员时,索引器将大大简化对数组或集合成员的存取操作

  • Async和Await使异步编程更简单

    C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作

  • 使用托管C++粘合C#和C++代码(一)

    C#在xml读写,数据库操纵,界面构造等很多方面性能卓越;C++的效率高,是底层开发的必备武器

  • C#基础概念之延迟加载

    延迟加载(lazy load)是Hibernate3关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作

  • 深入C# 序列化(Serialize)、反序列化(Deserialize)

    C#中的序列化和反序列化,序列化是.NET运行时环境用来支持用户定义类型的流化的机制