【问题标题】:Asynchronous PHP call which runs a controller method运行控制器方法的异步 PHP 调用
【发布时间】:2013-02-07 11:41:12
【问题描述】:

我想在按钮点击事件上执行:

localhost/codeigniter/controller/method

该方法将从网页中提取关键字并将其存储在数据库中。 其中有多个子方法也应该在后台运行。我不想让用户在此期间等待。 我读了this。这对我有用吗? 欢迎任何其他救生建议。

【问题讨论】:

    标签: php codeigniter asynchronous


    【解决方案1】:

    基于这个线程,我为我的 codeigniter 项目制作了这个。它工作得很好。您可以在后台处理任何函数。

    一个接受异步调用的控制器。

    class Daemon extends CI_Controller
    {
        // Remember to disable CI's csrf-checks for this controller
    
        function index( )
        {
            ignore_user_abort( 1 );
            try
            {
                if ( strcmp( $_SERVER['REMOTE_ADDR'], $_SERVER['SERVER_ADDR'] ) != 0 && !in_array( $_SERVER['REMOTE_ADDR'], $this->config->item( 'proxy_ips' ) ) )
                {
                    log_message( "error", "Daemon called from untrusted IP-address: " . $_SERVER['REMOTE_ADDR'] );
                    show_404( '/daemon' );
                    return;
                }
    
                $this->load->library( 'encrypt' );
                $params = unserialize( urldecode( $this->encrypt->decode( $_POST['data'] ) ) );
                unset( $_POST );
                $model = array_shift( $params );
                $method = array_shift( $params );
                $this->load->model( $model );
                if ( call_user_func_array( array( $this->$model, $method ), $params ) === FALSE )
                {
                    log_message( "error", "Daemon could not call: " . $model . "::" . $method . "()" );
                }
            }
            catch(Exception $e)
            {
                log_message( "error", "Daemon has error: " . $e->getMessage( ) . $e->getFile( ) . $e->getLine( ) );
            }
        }
    }
    

    还有一个执行异步调用的库

    class Daemon
    {
        public function execute_background( /* model, method, params */ )
        {
            $ci = &get_instance( );
            // The callback URL (its ourselves)
            $parts = parse_url( $ci->config->item( 'base_url' ) . "/daemon" );
            if ( strcmp( $parts['scheme'], 'https' ) == 0 )
            {
                $port = 443;
                $host = "ssl://" . $parts['host'];
            }
            else 
            {
                $port = 80;
                $host = $parts['host'];
            }
            if ( ( $fp = fsockopen( $host, isset( $parts['port'] ) ? $parts['port'] : $port, $errno, $errstr, 30 ) ) === FALSE )
            {
                throw new Exception( "Internal server error: background process could not be started" );
            }
            $ci->load->library( 'encrypt' );
            $post_string = "data=" . urlencode( $ci->encrypt->encode( serialize( func_get_args( ) ) ) );
            $out = "POST " . $parts['path'] . " HTTP/1.1\r\n";
            $out .= "Host: " . $host . "\r\n";
            $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
            $out .= "Content-Length: " . strlen( $post_string ) . "\r\n";
            $out .= "Connection: Close\r\n\r\n";
            $out .= $post_string;
            fwrite( $fp, $out );
            fclose( $fp );
        }
    }
    

    可以调用此方法来处理“后台”中的任何 model::method()。它使用可变参数。

    $this->load->library('daemon');
    $this->daemon->execute_background( 'model', 'method', $arg1, $arg2, ... );
    

    【讨论】:

    • 不能用于控制器方法?而且我没有任何 POST 数据,因此不需要 $params。那么这行得通吗?
    • 你试图提供一个线程的链接,在此基础上你创建了这个,但它实际上并不存在。
    • 我尝试将我的两种方法转换为模型。我运行了它们,但是第二种方法需要第一种方法的结果才能再次在后台执行。并且它不可用,因此返回未定义的错误。这在我的场景中不起作用。
    • 它可以在没有 $_POST 的情况下工作,只需修改它:) 这是一个通用的后台处理器。您不能将两者都放入模型中。控制器是从您自己的 PHP 进程调用的 Apache 调用的。
    • 这段 php 代码的哪一部分使 CI 异步?乍一看,这段代码似乎一点也不异步。
    【解决方案2】:

    你可以在socket中写:

    $fp = fsockopen($_SERVER['HTTP_HOST'], 80, $errno, $errstr, 30);
    $data = http_build_query($params, '', '&'); //$params - array with POST data
    fwrite($fp, "POST " . ('/controller/action') . " HTTP/1.1\r\n");
    fwrite($fp, "Host: ".$_SERVER['HTTP_HOST']."\r\n");
    fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
    fwrite($fp, "Content-Length: " . strlen($data) . "\r\n");
    fwrite($fp, "Connection: Close\r\n\r\n");
    fwrite($fp, $data);
    fclose($fp);
    

    【讨论】:

    • 我在问题中提到的网址会去哪里?
    • 没有 POST 数据提供给控制器方法。它已经可以从数据库中获得所有数据。我只是想调用该方法。 $params 不是必需的。我怎样才能调用该方法?
    猜你喜欢
    • 2017-05-19
    • 1970-01-01
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 2015-07-05
    • 1970-01-01
    相关资源
    最近更新 更多