4

For example, I want to continuously monitor a directory for the presence of .xml files.

As soon as a .xml file is found in that directory, the program should start processing on the file, e.g. reading the data inside the file, extracting useful data and further actions.

Solution I tried to use:

I tried to use an INFINITE while loop to continuously monitor the directory, and used glob() to check for the presence of files with .xml extension. glob() returns an array with paths of all files found.

So then within the infinite while loop, I check if the array returned by glob() is NON-EMPTY. If yes, then I read the file at each path in the array returned by glob() and do appropriate processing on the file.

The problem is that when i run it, I get

Fatal error: Maximum execution time of 30 seconds exceeded in C:\xampp\htdocs\Alpha\index.php on line 9

I believe this is due to the infinite while loop.

Questions:

  1. Is my way of solving my problem a good way?

  2. What should I do to bypass the above error?

Solace
  • 8,612
  • 22
  • 95
  • 183
  • 1
    You could use javascript `Server Sent Events` clientside and an infinite loop within a PHP script server side. The js client connects to the PHP script and receives any `Event-Stream` messages output by PHP. This would only run when you initiate the connection from the client whereas a cron job would run independently – Professor Abronsius Nov 13 '16 at 07:51

1 Answers1

2

As an example of using SSE to achieve your stated intention of monitoring a directory

The PHP script that does the directory scans - in this example it is a simple glob but could be much more sophisticated using recursiveIterator etc

<?php
    /*
        sse.php
    */
    set_time_limit( 0 );
    ini_set('auto_detect_line_endings', 1);
    ini_set('max_execution_time', '0');
    ob_end_clean();

    /* -- set headers -- */
    header('Content-Type: text/event-stream'); /* !important! */
    header('Cache-Control: no-cache');
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Allow-Methods: GET');
    header('Access-Control-Expose-Headers: X-Events');  

    /* -- utility function to send formatted sse message -- */
    if( !function_exists('sse_message') ){
        function sse_message( $evtname='dirmon', $data=null, $retry=1000 ){
            if( !is_null( $data ) ){
                echo "event:".$evtname."\r\n";
                echo "retry:".$retry."\r\n";
                echo "data:" . json_encode( $data, JSON_FORCE_OBJECT|JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS );
                echo "\r\n\r\n";
            }
        }
    }

    /* How often messages will be pushed to the client app */
    $sleep = 5;

    /* The directory to monitor */
    $dir = 'c:/temp/';

    /* The name of the event to monitor in js client app */
    $evt = 'dirmon';


    while( true ){
        if( connection_status() != CONNECTION_NORMAL or connection_aborted() ) {
            break;
        }

        /* Methods here to scan directory and produce data to send */
        $files=glob( $dir . '*.xml' );
        $count = count( $files );

        $payload=array(
            'dir'   =>  $dir,
            'files' =>  $count
        );

        /* -- prepare and send sse message -- */
        sse_message( $evt, $payload );

        /* -- Send output -- */
        if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
        @flush();

        /* wait */
        sleep( $sleep );
    }

    if( @ob_get_level() > 0 ) {
        for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
        @ob_end_clean();
    }
?>

The client page

<!doctype html>
<html>
    <head>
        <title>SSE</title>
        <script type='text/javascript'>
            var count=0;
            function bindEvtSource(){

                var evt='dirmon';
                var url='/sse.php';

                if ( !!window.EventSource ) {

                    var evtSource = new EventSource( url );

                    evtSource.addEventListener( 'open', function(e){
                        console.log(e.type);
                    },false);

                    evtSource.addEventListener( 'error', function(e){
                        console.error('%o %s',e,e.type);
                    },false);

                    evtSource.addEventListener( evt, function(e){
                        var json=JSON.parse(e.data);
                        var files=json.files;
                        if( files!=count ) {
                            count=files;
                            alert('contents changed - process changes! Send Ajax Request? etc etc');
                        }
                        document.getElementById('dirdata').innerHTML=e.data;
                    },false);



                } else {
                    alert('Server Sent Events are not supported in this browser');
                }
            }
            document.addEventListener( 'DOMContentLoaded', bindEvtSource, false );
        </script>
    </head>
    <body>
        <div id='dirdata'></div>
    </body>
</html>

You could use the response to then perform further actions by initiating a function within js - ie: send Ajax Request to a script that will do whatever processing you require ( Server Sent Events are uni-directional and you can send / receive - only receive! )

Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • Thank you so very much for your answer. Right now I am learning about CRON jobs, because I had started with it before I saw your answer. Since I am a newbie, it is taking some time. Once I am done, I will try your answer and read about Server End Scripts. Then I will accept your answer. Upvoting it right now – Solace Nov 13 '16 at 15:12