-
Bug
-
Resolution: Fixed
-
Minor
-
2.1, 2.2
-
MOODLE_21_STABLE, MOODLE_22_STABLE
-
MOODLE_23_STABLE
-
master-
MDL-31028_2 -
When an 'assessable_file_uploaded' event is to be processed in the Moodle cron job, depending on what operations have been performed earlier in the job, the 'stored_file' class may not yet be declared before the event data is unserialised. PHP will unserialise the objects but it substitutes an incomplete class type and the cron job will fail if any attempt is made to call methods of the file object contained in the event data.
To demonstrate this, I have attached a simple local plugin (eventtest.tar.gz) that implements an event handler that defers an 'assessable_file_uploaded' event to be processed in the cron job. Create a course in a test instance, add a file upload assignment (single or advanced, it doesn't matter), and submit a file. Then, run the Moodle cron job from the CLI repeatedly. Some executions will succeed if other earlier operations have called get_file_storage() or required lib/filelib.php, but if the events queue processing is the first time those classes are needed, they won't exist before the event handler is called, by which time the event data has been unserialised in events_process_queued_handler() and is an incomplete class. (See example output below.)
A simple solution for this specific problem is to add a hack in events_process_queued_handler() (patch attached) to pull in lib/filelib.php if the event being processed is 'assessable_file_uploaded', but the root of this issue is likely to come up for other classes if the same sort of circumstances happen there. Implementing autoloading may be one route around this, or avoid storing objects of any type but stdClass in event data.
fowlerj@q08-0967 ~/src/moodle-org.git $ sudo -u www-data php admin/cli/cron.php
|
Server Time: Thu, 05 Jan 2012 11:55:53 +1000
|
|
|
Running clean-up tasks...
|
Deleted old cache_text records
|
Executed tag cron
|
Cleaned up context instances
|
Built context paths
|
Cleaned cache flags
|
Cleaned up read notifications
|
...finished clean-up tasks
|
Created missing context instances
|
Cleaned up stale user sessions
|
Running auth crons if required...
|
Running enrol crons if required...
|
Running cron for enrol_cohort...
|
Starting activity modules
|
Processing module function assignment_cron ...... used 2 dbqueries
|
... used 0.052798986434937 seconds
|
done.
|
Processing module function forum_cron ...Starting digest processing...
|
Cleaned old digest records
|
... used 4 dbqueries
|
... used 0.048096179962158 seconds
|
done.
|
Finished activity modules
|
Starting blocks
|
Finished blocks
|
Starting quiz reports
|
Finished quiz reports
|
Starting admin reports
|
Finished admin reports
|
Starting main gradebook job...
|
done.
|
Starting processing the event queue...
|
*** in local_eventtest_handler::assessable_file_uploaded
|
*** class_exists(stored_file) = true
|
*** get_class($eventdata->files[e4a5b27283c568ae7e57014c3c2caf1b5c92d91e]) = stored_file
|
*** get_class($eventdata->files[807b87cb6e01ead5107e37722a29ff9b26552363]) = stored_file
|
*** get_class($eventdata->files[50afe513f4fef6e0d31952f79aec6b51e2ad7bb3]) = stored_file
|
done.
|
Starting course reports
|
Finished course reports
|
Starting gradebook plugins
|
Finished gradebook plugins
|
Fetching external blog entries...done.
|
Deleting blog associations linked to non-existent contexts...done.
|
Starting registration update on hubs...
|
Finished registration update on hubs.
|
Deleting session linked tokens more than one day old...done.
|
Starting admin tools
|
Processing cron function for tool_qeupgradehelper...
|
done. (1 dbqueries, 0 seconds)
|
Finished admin tools
|
Processing customized cron scripts ...done.
|
Checking automated backup status...INACTIVE
|
Deleting old draft files... done.
|
Cron script completed correctly
|
Execution took 0.573476 seconds
|
|
|
|
fowlerj@q08-0967 ~/src/moodle-org.git $ sudo -u www-data php admin/cli/cron.php
|
Server Time: Thu, 05 Jan 2012 11:55:55 +1000
|
|
|
Created missing context instances
|
Cleaned up stale user sessions
|
Running auth crons if required...
|
Running enrol crons if required...
|
Starting activity modules
|
Finished activity modules
|
Starting blocks
|
Finished blocks
|
Starting quiz reports
|
Finished quiz reports
|
Starting admin reports
|
Finished admin reports
|
Starting main gradebook job...
|
done.
|
Starting processing the event queue...
|
*** in local_eventtest_handler::assessable_file_uploaded
|
*** class_exists(stored_file) = false
|
*** get_class($eventdata->files[e4a5b27283c568ae7e57014c3c2caf1b5c92d91e]) = __PHP_Incomplete_Class
|
*** get_class($eventdata->files[807b87cb6e01ead5107e37722a29ff9b26552363]) = __PHP_Incomplete_Class
|
*** get_class($eventdata->files[50afe513f4fef6e0d31952f79aec6b51e2ad7bb3]) = __PHP_Incomplete_Class
|
PHP Fatal error: local_eventtest_handler::assessable_file_uploaded(): The script tried to execute a \
|
method or access a property of an incomplete object. Please ensure that the class definition \
|
"stored_file" of the object you are trying to operate on was loaded _before_ unserialize() gets \
|
called or provide a __autoload() function to load the class definition \
|
in /home/fowlerj/src/moodle-org.git/local/eventtest/lib.php on line 20
|
PHP Stack trace:
|
PHP 1. {main}() /home/fowlerj/src/moodle-org.git/admin/cli/cron.php:0
|
PHP 2. cron_run() /home/fowlerj/src/moodle-org.git/admin/cli/cron.php:61
|
PHP 3. events_cron() /home/fowlerj/src/moodle-org.git/lib/cronlib.php:342
|
PHP 4. events_process_queued_handler() /home/fowlerj/src/moodle-org.git/lib/eventslib.php:448
|
PHP 5. events_dispatch() /home/fowlerj/src/moodle-org.git/lib/eventslib.php:340
|
PHP 6. call_user_func() /home/fowlerj/src/moodle-org.git/lib/eventslib.php:296
|
PHP 7. local_eventtest_handler::assessable_file_uploaded() /home/fowlerj/src/moodle-org.git/lib/eventslib.php:0
|