Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
<?php

namespace Moodle;

use stdClass;
>
/** * Class */ class H5peditorFile { private $result, $field, $interface;
< public $type, $name, $path, $mime, $size;
> public $type, $name, $path, $mime, $size, $extension;
/** * Constructor. Process data for file uploaded through the editor. */ function __construct($interface) {
< $field = filter_input(INPUT_POST, 'field', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
> $field = filter_input(INPUT_POST, 'field', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
// Check for file upload. if ($field === NULL || empty($_FILES) || !isset($_FILES['file'])) { return; } $this->interface = $interface; // Create a new result object. $this->result = new stdClass(); // Get the field. $this->field = json_decode($field); // Handle temporarily uploaded form file if (function_exists('finfo_file')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->type = finfo_file($finfo, $_FILES['file']['tmp_name']); finfo_close($finfo); } elseif (function_exists('mime_content_type')) { // Deprecated, only when finfo isn't available. $this->type = mime_content_type($_FILES['file']['tmp_name']); } else { $this->type = $_FILES['file']['type']; } $this->extension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION); $this->size = $_FILES['file']['size']; } /** * Indicates if an uploaded file was found or not. * * @return boolean */ public function isLoaded() { return is_object($this->result); } /** * Check current file up agains mime types and extensions in the given list. * * @param array $mimes List to check against. * @return boolean */ public function check($mimes) { $ext = strtolower($this->extension); foreach ($mimes as $mime => $extension) { if (is_array($extension)) { // Multiple extensions if (in_array($ext, $extension)) { $this->type = $mime; return TRUE; } } elseif (/*$this->type === $mime && */$ext === $extension) { // TODO: Either remove everything that has to do with mime types, or make it work // Currently we're experiencing trouble with mime types on different servers... $this->type = $mime; return TRUE; } } return FALSE; } /** * Validate the file. * * @return boolean */ public function validate() { if (isset($this->result->error)) { return FALSE; } // Check for field type. if (!isset($this->field->type)) { $this->result->error = $this->interface->t('Unable to get field type.'); return FALSE; } $whitelist = explode(' ', $this->interface->getWhitelist( FALSE, H5PCore::$defaultContentWhitelist, H5PCore::$defaultLibraryWhitelistExtras )); // Check if mime type is allowed. $isValidMime = !isset($this->field->mimes) || in_array($this->type, $this->field->mimes); $isPhp = substr($this->extension, 0, 3) === 'php'; $isWhitelisted = in_array(strtolower($this->extension), $whitelist); if (!$isValidMime || !$isWhitelisted || $isPhp) { $this->result->error = $this->interface->t("File type isn't allowed."); return FALSE; } // Type specific validations. switch ($this->field->type) { default: $this->result->error = $this->interface->t('Invalid field type.'); return FALSE; case 'image': $allowed = array( 'image/png' => 'png', 'image/jpeg' => array('jpg', 'jpeg'), 'image/gif' => 'gif', ); if (!$this->check($allowed)) { $this->result->error = $this->interface->t('Invalid image file format. Use jpg, png or gif.'); return FALSE; } // Image size from temp file $image = @getimagesize($_FILES['file']['tmp_name']); if (!$image) { $this->result->error = $this->interface->t('File is not an image.'); return FALSE; } $this->result->width = $image[0]; $this->result->height = $image[1]; $this->result->mime = $this->type; break; case 'audio': $allowed = array( 'audio/mpeg' => 'mp3', 'audio/mp3' => 'mp3', 'audio/mp4' => 'm4a', 'audio/x-wav' => 'wav', 'audio/wav' => 'wav', //'application/ogg' => 'ogg', 'audio/ogg' => 'ogg', //'video/ogg' => 'ogg', ); if (!$this->check($allowed)) { $this->result->error = $this->interface->t('Invalid audio file format. Use mp3 or wav.'); return FALSE; } $this->result->mime = $this->type; break; case 'video': $allowed = array( 'video/mp4' => 'mp4', 'video/webm' => 'webm', // 'application/ogg' => 'ogv', 'video/ogg' => 'ogv', ); if (!$this->check($allowed)) { $this->result->error = $this->interface->t('Invalid video file format. Use mp4 or webm.'); return FALSE; } $this->result->mime = $this->type; break; case 'file': // TODO: Try to get file extension for type and check that it matches the current extension. $this->result->mime = $this->type; } return TRUE; } /** * Get the type of the current file. * * @return string */ public function getType() { return $this->field->type; } /** * Get the name of the current file. * * @return string */ public function getName() { static $name; if (empty($name)) { $name = uniqid($this->field->name . '-'); $matches = array(); preg_match('/([a-z0-9]{1,})$/i', $_FILES['file']['name'], $matches); if (isset($matches[0])) { $name .= '.' . $matches[0]; } } return $name; } /** * Get result from file processing. */ public function getResult() { return json_encode($this->result); } /** * Print result from file processing. */ public function printResult() { $this->result->path = $this->getType() . 's/' . $this->getName() . '#tmp'; // text/plain is used to support IE header('Cache-Control: no-cache'); header('Content-Type: text/plain; charset=utf-8'); print $this->getResult(); } }