web-dev-qa-db-ja.com

フィードのインポートを中断する方法

私はfetch_feedsを使ってWordPressに大量のフィードを更新しようとしています。予想されるように、50フィードを超えると、サーバーはタイムアウトし始めます。サーバーをクラッシュさせずにフィードをまとめて更新したいと思います。

あなたが私が物事を分解することができる方法を提案することができますか?たぶんAJAXを使っていますか?それは最高のテクニックですか?私が見ることができる例はありますか?

1
urok93

あなたが待ち行列に何も残らなくなるまで、あなたは10分ごとにフィードのインポートをプログラムする、wp cron関数を使うことを試みることができます。

コード例:

<?php
register_activation_hook( __FILE__, 'wp1903_schedule_cron' );

function wp1903_schedule_cron() {
    $counter = 0;
    $feeds = array(
        'http://example.com/feed1',
        'http://example.com/feed2',
        'http://example.com/feed3',
        'http://example.com/feed4'
    );

    foreach ($feeds as $feed) {
        $counter++;
        // schedule every 10 mins
        $time = time() + (600 * $counter);
        wp_schedule_single_event( $time, 'wp1903_process_feed', $feed );
    }
}

add_action('wp1903_process_feed', 'wp1903_import_feed');

function wp1903_import_feed($feed_url = '') {
    // do the import
}

アクティベーションフックでスケジューラを実行することだけが重要です。そうしないと、ページが読み込まれるたびにクローンのスケジュールが変更されます。

5
Dan Ștefancu

あなたは set_time_limit() でスクリプトの最大実行時間を延長しようとしましたか?これによってサーバーがクラッシュすることはありません(メモリー制限もあるため)。

set_time_limit( 0 ); // No time limit is imposed

私はあなたがスクリプトを「分解」することであなたが何を意味するのかわからない、あなたはそれについての第二の考えがあるかもしれません。

フィードのXMLに多数の行がある場合にできることは、独自のインポートスクリプトを作成し、小さい部分を少しずつ処理することによって独自の方法で処理することです。

$xml_handler = new ProductsParser();
$xml_parser  = xml_parser_create();

$source = '--URL--';

xml_set_object( $xml_parser, $xml_handler );
xml_parser_set_option( $xml_parser, XML_OPTION_CASE_FOLDING, false );
xml_set_element_handler( $xml_parser, 'startElement', 'endElement' );
xml_set_character_data_handler( $xml_parser, 'cdata' );

$fp = fopen ( $source, 'r' );
while ( $chunk = fread( $fp, 4096 ) ) {
  xml_parse( $xml_parser, $chunk, feof( $fp ) );
  flush();
}

fclose( $fp );

class ProductsParser {
  public $product; # Holds the record values
  public $elem_key; # Holds the current element key while reading
  public $record; # Holds the record tag

  function __construct( $args ) {
    $this->product  = false;
    $this->elem_key = false;
    $this->record   = '--RECORD-NAME--';
  }

  function startElement( $parser, $tag, $attributes ) {
    if ( $this->record == $tag && ! is_array( $this->product ) ) {
      $this->product = array();
    } elseif( is_array( $this->product ) ) {
      $this->elem_key = $tag;
    }
  }

  function endElement( $parser, $tag ) {
    if ( $this->record == $tag && is_array( $this->product ) ) {
      // Process the product row

      $this->product = false;
    } elseif ( is_array( $this->product ) && $this->elem_key != false ) {
      $this->elem_key = false;
    }
  }

  function cdata( $parser, $cdata ) {
    if ( is_array( $this->product ) && $this->elem_key != false ) {
      $this->product[$this->elem_key] = $cdata;
    }
  }
}

XMLパーサーについての詳細は PHPマニュアル にあります。

1
Mike Madern

実行時間が長いスクリプトについては、通常はajaxを使用してできるだけ簡単に分割しています。そのため、管理ページとajaxインポートループを作成するための概念クラスを次に示します。

<?php
class Ajax_Import{

    public function __construct(){
        if(is_admin()){
            add_action('admin_menu', array($this, 'add_plugin_page'));
        }
        add_action('wp_ajax_do_feed_import',array($this,'do_import'));
    }

    public function add_plugin_page(){
        // This page will be under "Settings"
        add_options_page('ajaxed Import', 'ajaxed Import', 'manage_options', 'test-setting-admin', array($this, 'create_admin_page'));
    }

    public function create_admin_page(){
        wp_enqueue_script( 'jquery');
        ?>
        <div class="wrap">
            <?php screen_icon(); ?>
            <h2><?php _e('AJAXed Import'); ?></h2>          
            <table class="form-table">
                <tbody>
                    <th scope="row">
                        <label for="my-text-field"><?php _e('Feeds To Import'); ?></label>
                    </th>
                    <td>
                        <textarea id="feeds"></textarea>
                        <br>
                        <span class="description"><?php _e('Enter Each feed in a new line.'); ?></span>
                    </td>
                </tbody>
            </table>
            <p class="submit"><input type="submit" id="do_import" value="Save Changes" class="button-primary" name="Submit"></p>
            <div id="import_status" style="display:none"></div>
        </div>
        <?php
        $this->import_loop_js();
    }

    public function do_import(){
        //do your import here ex:
        $rss = fetch_feed(esc_url( $_POST['feed_url']));
        if (!is_wp_error( $rss ) ) {
            $count = $rss->get_item_quantity(); 
            //do actuall import loop or whatever
            echo json_encode(array('message' => '<div id="message" class="success"><p>imported ' . $count . ' items from '.esc_url( $_POST['feed_url']).'</p></div>'));
        }else{
            echo json_encode(array('errors' => '<div id="message" class="error"><p>' . $rss->get_error_message() . '</p></div>'));
        }
        die();
    }

    public function import_loop_js(){
        ?>
        <script type="text/javascript">
        jQuery(document).ready(function($){
            var ajax_import = (function(){
                var instantiated;
                var feeds;
                function init (){
                    return {
                        start_import: function(){

                            instantiated.feeds = $("#feeds").val().split('\n');
                            instantiated.update_status('', true);
                            instantiated.next_feed();
                        },
                        make_ajax_call:function(feed){
                            data = {
                                action: "do_feed_import",
                                feed_url: feed
                            };
                            $.post( 
                                ajaxurl,
                                data, 
                                function(res){
                                    if (res.error){//add error message
                                        instantiated.update_status(res.error);
                                    }else{//add success message
                                        instantiated.update_status(res.message);
                                    }
                                    //call next feed
                                    instantiated.next_feed();
                                }, 
                                'json'
                            );
                        },
                        next_feed:function(){
                            if (instantiated.feeds.length > 0) {//if we have feeds in the list starts ajax calls
                                instantiated.make_ajax_call(instantiated.feeds.shift());
                            } else{
                                instantiated.update_status("all Done!!!");
                                $("#do_import").removeAttr("disabled");
                            }
                        },
                        update_status:function(m,clear){
                            clear = clear || false;
                            if (clear)
                                $("#import_status").html('').show();
                            else
                                $("#import_status").append(m);
                        }
                    }
                }

                return {
                    getInstance :function(){
                        if (!instantiated){
                            instantiated = init();
                        }
                        return instantiated; 
                    }
                }
            })();
            $("#do_import").on('click',function(){
                $(this).attr('disabled','disabled');
                ajax_import.getInstance().start_import();
            });
        });
        </script>
        <?php

    }
}

$Ajax_Import = new Ajax_Import();
1
Bainternet