[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Repository API unit tests 19 * 20 * @package repository 21 * @category phpunit 22 * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 global $CFG; 29 require_once("$CFG->dirroot/repository/lib.php"); 30 31 class core_repositorylib_testcase extends advanced_testcase { 32 33 /** 34 * Installing repository tests 35 * 36 * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org} 37 */ 38 public function test_install_repository() { 39 global $CFG, $DB; 40 41 $this->resetAfterTest(true); 42 43 $syscontext = context_system::instance(); 44 $repositorypluginname = 'boxnet'; 45 // override repository permission 46 $capability = 'repository/' . $repositorypluginname . ':view'; 47 $guestroleid = $DB->get_field('role', 'id', array('shortname' => 'guest')); 48 assign_capability($capability, CAP_ALLOW, $guestroleid, $syscontext->id, true); 49 50 $plugintype = new repository_type($repositorypluginname); 51 $pluginid = $plugintype->create(false); 52 $this->assertInternalType('int', $pluginid); 53 $args = array(); 54 $args['type'] = $repositorypluginname; 55 $repos = repository::get_instances($args); 56 $repository = reset($repos); 57 $this->assertInstanceOf('repository', $repository); 58 $info = $repository->get_meta(); 59 $this->assertEquals($repositorypluginname, $info->type); 60 } 61 62 public function test_get_unused_filename() { 63 global $USER; 64 65 $this->resetAfterTest(true); 66 67 $this->setAdminUser(); 68 $fs = get_file_storage(); 69 70 $draftitemid = null; 71 $context = context_user::instance($USER->id); 72 file_prepare_draft_area($draftitemid, $context->id, 'phpunit', 'test_get_unused_filename', 1); 73 74 $dummy = array( 75 'contextid' => $context->id, 76 'component' => 'user', 77 'filearea' => 'draft', 78 'itemid' => $draftitemid, 79 'filepath' => '/', 80 'filename' => '' 81 ); 82 83 // Create some files. 84 $existingfiles = array( 85 'test', 86 'test.txt', 87 'test (1).txt', 88 'test1.txt', 89 'test1 (1).txt', 90 'test1 (2).txt', 91 'test1 (3).txt', 92 'test1 (My name is Bob).txt', 93 'test2 (555).txt', 94 'test3 (1000).txt', 95 'test3 (1000MB).txt', 96 ); 97 foreach ($existingfiles as $filename) { 98 $dummy['filename'] = $filename; 99 $file = $fs->create_file_from_string($dummy, 'blah! ' . $filename); 100 $this->assertTrue(repository::draftfile_exists($draftitemid, '/', $filename)); 101 } 102 103 // Actual testing. 104 $this->assertEquals('free.txt', repository::get_unused_filename($draftitemid, '/', 'free.txt')); 105 $this->assertEquals('test (1)', repository::get_unused_filename($draftitemid, '/', 'test')); 106 $this->assertEquals('test (2).txt', repository::get_unused_filename($draftitemid, '/', 'test.txt')); 107 $this->assertEquals('test1 (4).txt', repository::get_unused_filename($draftitemid, '/', 'test1.txt')); 108 $this->assertEquals('test1 (8).txt', repository::get_unused_filename($draftitemid, '/', 'test1 (8).txt')); 109 $this->assertEquals('test1 ().txt', repository::get_unused_filename($draftitemid, '/', 'test1 ().txt')); 110 $this->assertEquals('test2 (556).txt', repository::get_unused_filename($draftitemid, '/', 'test2 (555).txt')); 111 $this->assertEquals('test3 (1001).txt', repository::get_unused_filename($draftitemid, '/', 'test3 (1000).txt')); 112 $this->assertEquals('test3 (1000MB) (1).txt', repository::get_unused_filename($draftitemid, '/', 'test3 (1000MB).txt')); 113 $this->assertEquals('test4 (1).txt', repository::get_unused_filename($draftitemid, '/', 'test4 (1).txt')); 114 } 115 116 public function test_draftfile_exists() { 117 global $USER; 118 119 $this->resetAfterTest(true); 120 121 $this->setAdminUser(); 122 $fs = get_file_storage(); 123 124 $draftitemid = file_get_unused_draft_itemid(); 125 $context = context_user::instance($USER->id); 126 127 $dummy = array( 128 'contextid' => $context->id, 129 'component' => 'user', 130 'filearea' => 'draft', 131 'itemid' => $draftitemid, 132 'filepath' => '/', 133 'filename' => '' 134 ); 135 136 // Create some files. 137 $existingfiles = array( 138 'The Matrix.movie', 139 'Astalavista.txt', 140 'foobar', 141 ); 142 foreach ($existingfiles as $filename) { 143 $dummy['filename'] = $filename; 144 $file = $fs->create_file_from_string($dummy, 'Content of ' . $filename); 145 $this->assertInstanceOf('stored_file', $file); 146 } 147 148 // Doing the text. 149 foreach ($existingfiles as $filename) { 150 $this->assertTrue(repository::draftfile_exists($draftitemid, '/', $filename)); 151 } 152 foreach (array('Terminator.movie', 'Where is Wally?', 'barfoo') as $filename) { 153 $this->assertFalse(repository::draftfile_exists($draftitemid, '/', $filename)); 154 } 155 } 156 157 public function test_can_be_edited_by_user() { 158 $this->resetAfterTest(true); 159 160 $syscontext = context_system::instance(); 161 $course = $this->getDataGenerator()->create_course(); 162 $coursecontext = context_course::instance($course->id); 163 $roleid = create_role('A role', 'arole', 'A role', ''); 164 $user = $this->getDataGenerator()->create_user(); 165 $this->setUser($user); 166 167 // Instance on a site level. 168 $this->getDataGenerator()->create_repository_type('flickr_public'); 169 $repoid = $this->getDataGenerator()->create_repository('flickr_public')->id; 170 $systemrepo = repository::get_repository_by_id($repoid, $syscontext); 171 172 role_assign($roleid, $user->id, $syscontext->id); 173 assign_capability('moodle/site:config', CAP_ALLOW, $roleid, $syscontext, true); 174 assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $syscontext, true); 175 accesslib_clear_all_caches_for_unit_testing(); 176 $this->assertTrue($systemrepo->can_be_edited_by_user()); 177 178 assign_capability('repository/flickr_public:view', CAP_PROHIBIT, $roleid, $syscontext, true); 179 assign_capability('moodle/site:config', CAP_PROHIBIT, $roleid, $syscontext, true); 180 accesslib_clear_all_caches_for_unit_testing(); 181 $this->assertFalse($systemrepo->can_be_edited_by_user()); 182 183 assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $syscontext, true); 184 assign_capability('moodle/site:config', CAP_PROHIBIT, $roleid, $syscontext, true); 185 accesslib_clear_all_caches_for_unit_testing(); 186 $this->assertFalse($systemrepo->can_be_edited_by_user()); 187 188 role_unassign($roleid, $user->id, $syscontext->id); 189 accesslib_clear_all_caches_for_unit_testing(); 190 191 // Instance on a course level. 192 $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleid); 193 194 $params = array('contextid' => $coursecontext->id); 195 $repoid = $this->getDataGenerator()->create_repository('flickr_public', $params)->id; 196 $courserepo = repository::get_repository_by_id($repoid, $coursecontext); 197 198 assign_capability('moodle/course:update', CAP_ALLOW, $roleid, $coursecontext, true); 199 assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $coursecontext, true); 200 accesslib_clear_all_caches_for_unit_testing(); 201 $this->assertTrue($courserepo->can_be_edited_by_user()); 202 203 assign_capability('repository/flickr_public:view', CAP_PROHIBIT, $roleid, $coursecontext, true); 204 accesslib_clear_all_caches_for_unit_testing(); 205 $this->assertFalse($courserepo->can_be_edited_by_user()); 206 207 assign_capability('moodle/course:update', CAP_ALLOW, $roleid, $coursecontext, true); 208 assign_capability('repository/flickr_public:view', CAP_PROHIBIT, $roleid, $coursecontext, true); 209 accesslib_clear_all_caches_for_unit_testing(); 210 $this->assertFalse($courserepo->can_be_edited_by_user()); 211 212 role_unassign($roleid, $user->id, $coursecontext->id); 213 accesslib_clear_all_caches_for_unit_testing(); 214 215 // Instance on a user level. 216 $otheruser = $this->getDataGenerator()->create_user(); 217 $otherusercontext = context_user::instance($otheruser->id); 218 role_assign($roleid, $user->id, $syscontext->id); 219 assign_capability('repository/flickr_public:view', CAP_ALLOW, $roleid, $syscontext, true); 220 accesslib_clear_all_caches_for_unit_testing(); 221 222 // Editing someone else's instance. 223 $record = array('contextid' => $otherusercontext->id); 224 $repoid = $this->getDataGenerator()->create_repository('flickr_public', $record)->id; 225 $userrepo = repository::get_repository_by_id($repoid, $syscontext); 226 $this->assertFalse($userrepo->can_be_edited_by_user()); 227 228 // Editing my own instance. 229 $usercontext = context_user::instance($user->id); 230 $record = array('contextid' => $usercontext->id); 231 $repoid = $this->getDataGenerator()->create_repository('flickr_public', $record)->id; 232 $userrepo = repository::get_repository_by_id($repoid, $syscontext); 233 $this->assertTrue($userrepo->can_be_edited_by_user()); 234 235 } 236 237 public function test_check_capability() { 238 $this->resetAfterTest(true); 239 240 $syscontext = context_system::instance(); 241 $course1 = $this->getDataGenerator()->create_course(); 242 $course1context = context_course::instance($course1->id); 243 $course2 = $this->getDataGenerator()->create_course(); 244 $course2context = context_course::instance($course2->id); 245 246 $forumdata = new stdClass(); 247 $forumdata->course = $course1->id; 248 $forumc1 = $this->getDataGenerator()->create_module('forum', $forumdata); 249 $forumc1context = context_module::instance($forumc1->cmid); 250 $forumdata->course = $course2->id; 251 $forumc2 = $this->getDataGenerator()->create_module('forum', $forumdata); 252 $forumc2context = context_module::instance($forumc2->cmid); 253 254 $blockdata = new stdClass(); 255 $blockdata->parentcontextid = $course1context->id; 256 $blockc1 = $this->getDataGenerator()->create_block('online_users', $blockdata); 257 $blockc1context = context_block::instance($blockc1->id); 258 $blockdata->parentcontextid = $course2context->id; 259 $blockc2 = $this->getDataGenerator()->create_block('online_users', $blockdata); 260 $blockc2context = context_block::instance($blockc2->id); 261 262 $user1 = $this->getDataGenerator()->create_user(); 263 $user1context = context_user::instance($user1->id); 264 $user2 = $this->getDataGenerator()->create_user(); 265 $user2context = context_user::instance($user2->id); 266 267 // New role prohibiting Flickr Public access. 268 $roleid = create_role('No Flickr Public', 'noflickrpublic', 'No Flickr Public', ''); 269 assign_capability('repository/flickr_public:view', CAP_PROHIBIT, $roleid, $syscontext, true); 270 271 // Disallow system access to Flickr Public to user 2. 272 role_assign($roleid, $user2->id, $syscontext->id); 273 accesslib_clear_all_caches_for_unit_testing(); 274 275 // Enable repositories. 276 $this->getDataGenerator()->create_repository_type('flickr_public'); 277 $this->getDataGenerator()->create_repository_type('dropbox'); 278 279 // Instance on a site level. 280 $repoid = $this->getDataGenerator()->create_repository('flickr_public')->id; 281 $systemrepo = repository::get_repository_by_id($repoid, $syscontext); 282 283 // Check that everyone with right capability can view a site-wide repository. 284 $this->setUser($user1); 285 $this->assertTrue($systemrepo->check_capability()); 286 287 // Without the capability, we cannot view a site-wide repository. 288 $this->setUser($user2); 289 $caughtexception = false; 290 try { 291 $systemrepo->check_capability(); 292 } catch (repository_exception $e) { 293 $caughtexception = true; 294 } 295 $this->assertTrue($caughtexception); 296 297 // Instance on a course level. 298 $record = new stdClass(); 299 $record->contextid = $course1context->id; 300 $courserepoid = $this->getDataGenerator()->create_repository('flickr_public', $record)->id; 301 302 // Within the course, I can view the repository. 303 $courserepo = repository::get_repository_by_id($courserepoid, $course1context); 304 $this->setUser($user1); 305 $this->assertTrue($courserepo->check_capability()); 306 // But not without the capability. 307 $this->setUser($user2); 308 $caughtexception = false; 309 try { 310 $courserepo->check_capability(); 311 } catch (repository_exception $e) { 312 $caughtexception = true; 313 } 314 $this->assertTrue($caughtexception); 315 316 // From another course I cannot, with or without the capability. 317 $courserepo = repository::get_repository_by_id($courserepoid, $course2context); 318 $this->setUser($user1); 319 $caughtexception = false; 320 try { 321 $courserepo->check_capability(); 322 } catch (repository_exception $e) { 323 $caughtexception = true; 324 } 325 $this->assertTrue($caughtexception); 326 $this->setUser($user2); 327 $caughtexception = false; 328 try { 329 $courserepo->check_capability(); 330 } catch (repository_exception $e) { 331 $caughtexception = true; 332 } 333 $this->assertTrue($caughtexception); 334 335 // From a module within the course, I can view the repository. 336 $courserepo = repository::get_repository_by_id($courserepoid, $forumc1context); 337 $this->setUser($user1); 338 $this->assertTrue($courserepo->check_capability()); 339 // But not without the capability. 340 $this->setUser($user2); 341 $caughtexception = false; 342 try { 343 $courserepo->check_capability(); 344 } catch (repository_exception $e) { 345 $caughtexception = true; 346 } 347 $this->assertTrue($caughtexception); 348 349 // From a module in the wrong course, I cannot view the repository. 350 $courserepo = repository::get_repository_by_id($courserepoid, $forumc2context); 351 $this->setUser($user1); 352 $caughtexception = false; 353 try { 354 $courserepo->check_capability(); 355 } catch (repository_exception $e) { 356 $caughtexception = true; 357 } 358 $this->assertTrue($caughtexception); 359 360 // From a block within the course, I can view the repository. 361 $courserepo = repository::get_repository_by_id($courserepoid, $blockc1context); 362 $this->setUser($user1); 363 $this->assertTrue($courserepo->check_capability()); 364 // But not without the capability. 365 $this->setUser($user2); 366 $caughtexception = false; 367 try { 368 $courserepo->check_capability(); 369 } catch (repository_exception $e) { 370 $caughtexception = true; 371 } 372 $this->assertTrue($caughtexception); 373 374 // From a block in the wrong course, I cannot view the repository. 375 $courserepo = repository::get_repository_by_id($courserepoid, $blockc2context); 376 $this->setUser($user1); 377 $caughtexception = false; 378 try { 379 $courserepo->check_capability(); 380 } catch (repository_exception $e) { 381 $caughtexception = true; 382 } 383 $this->assertTrue($caughtexception); 384 385 // Instance on a user level. 386 // Instance on a course level. 387 $record = new stdClass(); 388 $record->contextid = $user1context->id; 389 $user1repoid = $this->getDataGenerator()->create_repository('flickr_public', $record)->id; 390 $record->contextid = $user2context->id; 391 $user2repoid = $this->getDataGenerator()->create_repository('flickr_public', $record)->id; 392 393 // Check that a user can see its own repository. 394 $userrepo = repository::get_repository_by_id($user1repoid, $syscontext); 395 $this->setUser($user1); 396 $this->assertTrue($userrepo->check_capability()); 397 // But not without the capability. 398 $userrepo = repository::get_repository_by_id($user2repoid, $syscontext); 399 $this->setUser($user2); 400 $caughtexception = false; 401 try { 402 $userrepo->check_capability(); 403 } catch (repository_exception $e) { 404 $caughtexception = true; 405 } 406 $this->assertTrue($caughtexception); 407 408 // Check that a user cannot see someone's repository. 409 $userrepo = repository::get_repository_by_id($user2repoid, $syscontext); 410 $this->setUser($user1); 411 $caughtexception = false; 412 try { 413 $userrepo->check_capability(); 414 } catch (repository_exception $e) { 415 $caughtexception = true; 416 } 417 $this->assertTrue($caughtexception); 418 // Make sure the repo from user 2 was accessible. 419 role_unassign($roleid, $user2->id, $syscontext->id); 420 accesslib_clear_all_caches_for_unit_testing(); 421 $this->setUser($user2); 422 $this->assertTrue($userrepo->check_capability()); 423 role_assign($roleid, $user2->id, $syscontext->id); 424 accesslib_clear_all_caches_for_unit_testing(); 425 426 // Check that a user can view SOME repositories when logged in as someone else. 427 $params = new stdClass(); 428 $params->name = 'Dropbox'; 429 $params->dropbox_key = 'key'; 430 $params->dropbox_secret = 'secret'; 431 $privaterepoid = $this->getDataGenerator()->create_repository('dropbox')->id; 432 $notprivaterepoid = $this->getDataGenerator()->create_repository('upload')->id; 433 434 $privaterepo = repository::get_repository_by_id($privaterepoid, $syscontext); 435 $notprivaterepo = repository::get_repository_by_id($notprivaterepoid, $syscontext); 436 $userrepo = repository::get_repository_by_id($user1repoid, $syscontext); 437 438 $this->setAdminUser(); 439 \core\session\manager::loginas($user1->id, $syscontext); 440 441 // Logged in as, I cannot view a user instance. 442 $caughtexception = false; 443 try { 444 $userrepo->check_capability(); 445 } catch (repository_exception $e) { 446 $caughtexception = true; 447 } 448 $this->assertTrue($caughtexception); 449 450 // Logged in as, I cannot view a private instance. 451 $caughtexception = false; 452 try { 453 $privaterepo->check_capability(); 454 } catch (repository_exception $e) { 455 $caughtexception = true; 456 } 457 $this->assertTrue($caughtexception); 458 459 // Logged in as, I can view a non-private instance. 460 $this->assertTrue($notprivaterepo->check_capability()); 461 } 462 463 function test_delete_all_for_context() { 464 global $DB; 465 $this->resetAfterTest(true); 466 467 $this->setAdminUser(); 468 $course = $this->getDataGenerator()->create_course(); 469 $user = $this->getDataGenerator()->create_user(); 470 $this->getDataGenerator()->create_repository_type('flickr_public'); 471 $this->getDataGenerator()->create_repository_type('filesystem'); 472 $coursecontext = context_course::instance($course->id); 473 $usercontext = context_user::instance($user->id); 474 475 // Creating course instances. 476 $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id)); 477 $courserepo1 = repository::get_repository_by_id($repo->id, $coursecontext); 478 $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); 479 480 $repo = $this->getDataGenerator()->create_repository('filesystem', array('contextid' => $coursecontext->id)); 481 $courserepo2 = repository::get_repository_by_id($repo->id, $coursecontext); 482 $this->assertEquals(2, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); 483 484 // Creating user instances. 485 $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id)); 486 $userrepo1 = repository::get_repository_by_id($repo->id, $usercontext); 487 $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); 488 489 $repo = $this->getDataGenerator()->create_repository('filesystem', array('contextid' => $usercontext->id)); 490 $userrepo2 = repository::get_repository_by_id($repo->id, $usercontext); 491 $this->assertEquals(2, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); 492 493 // Simulation of course deletion. 494 repository::delete_all_for_context($coursecontext->id); 495 $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); 496 $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $courserepo1->id))); 497 $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $courserepo2->id))); 498 $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $courserepo1->id))); 499 $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $courserepo2->id))); 500 501 // Simulation of user deletion. 502 repository::delete_all_for_context($usercontext->id); 503 $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); 504 $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $userrepo1->id))); 505 $this->assertEquals(0, $DB->count_records('repository_instances', array('id' => $userrepo2->id))); 506 $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $userrepo1->id))); 507 $this->assertEquals(0, $DB->count_records('repository_instance_config', array('instanceid' => $userrepo2->id))); 508 509 // Checking deletion upon course context deletion. 510 $course = $this->getDataGenerator()->create_course(); 511 $coursecontext = context_course::instance($course->id); 512 $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id)); 513 $courserepo = repository::get_repository_by_id($repo->id, $coursecontext); 514 $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); 515 $coursecontext->delete(); 516 $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); 517 518 // Checking deletion upon user context deletion. 519 $user = $this->getDataGenerator()->create_user(); 520 $usercontext = context_user::instance($user->id); 521 $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id)); 522 $userrepo = repository::get_repository_by_id($repo->id, $usercontext); 523 $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); 524 $usercontext->delete(); 525 $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); 526 527 // Checking deletion upon course deletion. 528 $course = $this->getDataGenerator()->create_course(); 529 $coursecontext = context_course::instance($course->id); 530 $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $coursecontext->id)); 531 $courserepo = repository::get_repository_by_id($repo->id, $coursecontext); 532 $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); 533 delete_course($course, false); 534 $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $coursecontext->id))); 535 536 // Checking deletion upon user deletion. 537 $user = $this->getDataGenerator()->create_user(); 538 $usercontext = context_user::instance($user->id); 539 $repo = $this->getDataGenerator()->create_repository('flickr_public', array('contextid' => $usercontext->id)); 540 $userrepo = repository::get_repository_by_id($repo->id, $usercontext); 541 $this->assertEquals(1, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); 542 delete_user($user); 543 $this->assertEquals(0, $DB->count_records('repository_instances', array('contextid' => $usercontext->id))); 544 } 545 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |