11namespace Depage\HtmlForm\Elements;
13use Depage\HtmlForm\Abstracts;
52 parent::setDefaults();
55 $this->defaults[
'maxNum'] = 1;
56 $this->defaults[
'maxSize'] =
false;
57 $this->defaults[
'allowedExtensions'] =
"";
67 if ($this->maxSize !==
false) {
68 $maxInput =
"<input type=\"hidden\" name=\"MAX_FILE_SIZE\" value=\"{$this->maxSize}\" />";
76 $label = $this->htmlLabel();
82 return "<p {$wrapperAttributes}>" .
84 "<span class=\"depage-label\">{$label}{$marker}</span>" .
86 "<input name=\"{$this->name}[]\" type=\"{$this->type}\"{$inputAttributes}>" .
100 $attributes = parent::htmlInputAttributes();
102 if ($this->maxNum > 1) {
103 $attributes .=
" multiple=\"multiple\"";
105 if (!empty($this->allowedExtensions)) {
106 $attributes .=
" accept=\"" . htmlentities($this->allowedExtensions) .
"\"";
119 $this->value = (array) $this->value;
129 if (!is_array($files)) {
133 if (!empty($this->allowedExtensions)) {
134 $extRegex = str_replace([
" ",
",",
"."], [
"",
"|",
"\."], $this->allowedExtensions);
136 if (isset($_FILES[$this->name])) {
137 foreach ($_FILES[$this->name][
"error"] as $key => $error) {
138 if (!empty($extRegex) && !preg_match(
"/.*(" . $extRegex .
")$/i", $_FILES[$this->name][
"name"][$key])) {
139 $error = self::UPLOAD_ERR_FILE_EXTENSION;
141 if ($error == UPLOAD_ERR_OK) {
142 $uploadName = $_FILES[
$this->name][
"tmp_name"][$key];
143 $safeFilename = $this->
sanitizeFilename($_FILES[$this->name][
"name"][$key]);
146 if (function_exists(
'finfo_open') && $this->
isAllowedMimeType($uploadName, $safeFilename)) {
147 $uploadName = $uploadName;
149 $this->
log(
"htmlform: Uploaded file has disallowed MIME type.");
150 $error = self::UPLOAD_ERR_FILE_EXTENSION;
153 if ($error == UPLOAD_ERR_OK) {
154 $tmpName = sys_get_temp_dir() .
'/htmlforms/' . session_id() .
'_' . uniqid(
'depage-form-upload-',
true);
155 $success = move_uploaded_file($uploadName, $tmpName);
157 $this->
log(
"htmlform: Failed to move uploaded file to secure temp location.");
158 $error = UPLOAD_ERR_CANT_WRITE;
162 if ($error == UPLOAD_ERR_OK) {
163 if ($this->maxNum > 1) {
165 'name' => $safeFilename,
166 'tmp_name' => $tmpName,
171 'name' => $safeFilename,
172 'tmp_name' => $tmpName,
176 if (isset($tmpName) && file_exists($tmpName)) {
182 UPLOAD_ERR_INI_SIZE =>
"The uploaded file exceeds the upload_max_filesize directive in php.ini.",
183 UPLOAD_ERR_FORM_SIZE =>
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.",
184 UPLOAD_ERR_PARTIAL =>
"The uploaded file was only partially uploaded.",
185 UPLOAD_ERR_NO_FILE =>
"No file was uploaded.",
186 UPLOAD_ERR_NO_TMP_DIR =>
"Missing a temporary folder.",
187 UPLOAD_ERR_CANT_WRITE =>
"Failed to write file to disk.",
188 UPLOAD_ERR_EXTENSION =>
"A PHP extension stopped the file upload. PHP does not provide a way to ascertain which extension caused the file upload to stop.",
189 self::UPLOAD_ERR_FILE_EXTENSION =>
"The uploaded file has an unallowed extension.",
191 $this->
log(
"htmlform: " . $errorMsgs[$error]);
199 $this->value = array_slice($files, - $this->maxNum, $this->maxNum);
213 $filename = basename($filename);
216 $filename = preg_replace(
'/[\x00-\x1f\x7f]/',
'', $filename);
219 $filename = preg_replace(
'/[^a-zA-Z0-9\.\-_]/',
'_', $filename);
220 $filename = substr($filename, 0, 255);
223 $filename = ltrim($filename,
'.');
226 $filename = preg_replace(
'/[^a-zA-Z0-9\.\-_]/',
'', $filename);
228 return !empty($filename) ? $filename :
'uploaded_file';
240 'jpg' => [
'image/jpeg'],
241 'jpeg' => [
'image/jpeg'],
242 'png' => [
'image/png'],
243 'gif' => [
'image/gif'],
244 'bmp' => [
'image/bmp'],
245 'webp' => [
'image/webp'],
246 'tiff' => [
'image/tiff'],
247 'svg' => [
'image/svg+xml'],
248 'pdf' => [
'application/pdf'],
249 'doc' => [
'application/msword'],
250 'docx' => [
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
251 'xls' => [
'application/vnd.ms-excel'],
252 'xlsx' => [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
253 'csv' => [
'text/csv'],
254 'txt' => [
'text/plain'],
255 'rtf' => [
'application/rtf'],
256 'odt' => [
'application/vnd.oasis.opendocument.text'],
257 'ods' => [
'application/vnd.oasis.opendocument.spreadsheet'],
258 'zip' => [
'application/zip'],
259 'gz' => [
'application/gzip'],
260 'tar' => [
'application/x-tar'],
261 'xml' => [
'application/xml',
'text/xml'],
262 'json' => [
'application/json'],
263 'mp3' => [
'audio/mpeg'],
264 'mp4' => [
'video/mp4'],
265 'mpeg' => [
'video/mpeg'],
266 'ogg' => [
'application/ogg',
'audio/ogg'],
267 'ogv' => [
'video/ogg'],
268 'webm' => [
'video/webm'],
269 'aac' => [
'audio/aac'],
270 'wav' => [
'audio/wav'],
271 'eps' => [
'application/postscript'],
272 'ps' => [
'application/postscript'],
276 if (!empty($this->allowedExtensions)) {
277 $extensions = array_map(
'trim', explode(
',', $this->allowedExtensions));
278 foreach ($extensions as $ext) {
279 $ext = strtolower($ext);
280 if (isset($extensionMap[$ext])) {
281 $allowedMimes = array_merge($allowedMimes, $extensionMap[$ext]);
286 return $allowedMimes;
301 if (empty($allowedMimes)) {
306 if (function_exists(
'finfo_open')) {
307 $finfo = finfo_open(FILEINFO_MIME_TYPE);
308 $mimeType = finfo_file($finfo, $uploadPath);
312 $ext = strtolower(pathinfo($safeFilename, PATHINFO_EXTENSION));
314 'jpg' =>
'image/jpeg',
'jpeg' =>
'image/jpeg',
'png' =>
'image/png',
315 'gif' =>
'image/gif',
'bmp' =>
'image/bmp',
'webp' =>
'image/webp',
316 'pdf' =>
'application/pdf',
'zip' =>
'application/zip',
318 $mimeType = $extMap[$ext] ??
'application/octet-stream';
321 return in_array($mimeType, $allowedMimes);
341 if (count($this->value)) {
342 foreach ($this->value as $file) {
343 if (file_exists($file[
'tmp_name'])) {
344 unlink($file[
'tmp_name']);
log(string $argument, ?string $type=null)
error & warning logger
htmlList(?array $options=null, array|string|null $value=null)
Renders HTML datalist.
$label
Input element - HTML label.
$errorMessage
Message that gets displayed in case of invalid input.
htmlHelpMessage()
Returns HTML-rendered helpMessage.
htmlWrapperAttributes()
Returns string of HTML attributes for element wrapper paragraph.
htmlMarker()
Returns elements' required-indicator.
$helpMessage
Extra help message.
htmlValue()
Returns HTML-rendered element value.
$marker
Input element - HTML marker text that marks required fields.
htmlErrorMessage()
Returns HTML-rendered error message.
htmlInputAttributes()
renders text element specific HTML attributes
$maxSize
HTML maxSize attribute.
clearValue()
resets the value to en empty array and cleans uploaded files
typeCastValue()
Converts value to element specific type.
$maxNum
HTML maxNum attribute.
getAllowedMimeTypes()
Returns the list of allowed MIME types based on allowedExtensions.
handleUploadedFiles(?array $files=null)
saves uploaded files
__toString()
Renders element to HTML.
clearUploadedFiles()
cleans uploaded files when session is cleared
$allowedExtensions
HTML allowedExtensions attribute.
isAllowedMimeType(string $uploadPath, string $safeFilename)
Checks if a file's MIME type is allowed.
sanitizeFilename(string $filename)
Sanitizes a filename to prevent directory traversal and injection.
setDefaults()
collects initial values across subclasses
const UPLOAD_ERR_FILE_EXTENSION