field_key( $field ); } /** * The file types allowed for this field. * * @param array $field The field settings. * * @return array */ public function allowed_types( $field ) { $raw = isset( $field['file_types'] ) ? (string) $field['file_types'] : ''; if ( '' === trim( $raw ) ) { return Ranq_Forms_Uploads::default_types(); } $list = array(); foreach ( preg_split( '/[\s,]+/', strtolower( $raw ) ) as $ext ) { $ext = ltrim( trim( $ext ), '.' ); $ext = preg_replace( '/[^a-z0-9]/', '', $ext ); // What is forbidden stays forbidden even when someone types it in by hand. if ( '' !== $ext && ! in_array( $ext, Ranq_Forms_Uploads::forbidden(), true ) ) { $list[] = $ext; } } return $list ? array_values( array_unique( $list ) ) : Ranq_Forms_Uploads::default_types(); } /** * The largest size for this field, in bytes. * * Never more than what the server itself allows, whatever the settings say. * * @param array $field The field settings. * * @return int */ public function max_size( $field ) { $server = Ranq_Forms_Uploads::server_limit(); $wanted = isset( $field['max_size'] ) ? (int) $field['max_size'] : 0; if ( $wanted < 1 ) { return $server; } return min( $server, $wanted * MB_IN_BYTES ); } /** * How many files at most. * * @param array $field The field settings. * * @return int */ public function max_files( $field ) { $count = isset( $field['max_files'] ) ? (int) $field['max_files'] : 1; return max( 1, min( 10, $count ) ); } /** * The settings. * * @return array */ public function get_settings() { $settings = parent::get_settings(); $settings['basic'][] = array( 'key' => 'file_types', 'type' => 'text', 'label' => __( 'Allowed file types', '2ranq-forms' ), 'help' => sprintf( /* translators: %s: default list of file types. */ __( 'Separate with commas. Leave empty for: %s', '2ranq-forms' ), implode( ', ', Ranq_Forms_Uploads::default_types() ) ), ); $settings['basic'][] = array( 'key' => 'max_size', 'type' => 'number', 'label' => __( 'Largest file, in MB', '2ranq-forms' ), 'help' => sprintf( /* translators: %s: server limit, for example 64 MB. */ __( 'This server allows up to %s no matter what you put here.', '2ranq-forms' ), size_format( Ranq_Forms_Uploads::server_limit() ) ), ); $settings['basic'][] = array( 'key' => 'max_files', 'type' => 'number', 'label' => __( 'How many files', '2ranq-forms' ), 'help' => __( 'Between 1 and 10.', '2ranq-forms' ), ); return $settings; } /** * Prints the field. * * @param array $field The field settings. * @param int $form_id The form id. * * @return void */ public function render( $field, $form_id ) { $describedby = $this->describedby( $field, $form_id ); $id = $this->input_id( $field, $form_id ); $types = $this->allowed_types( $field ); $multiple = $this->max_files( $field ) > 1; $accept = array(); foreach ( $types as $ext ) { $accept[] = '.' . $ext; } ?>
wrapper_data( $field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped in wrapper_data().?>> render_label( $field, $form_id ); ?>
aria-describedby="" />
render_description( $field, $form_id ); ?>
input_name( $field ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- the nonce is checked before the call, in Ranq_Forms_Submission. if ( ! isset( $_FILES[ $name ] ) ) { return array(); } // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- every file goes through the full check in Ranq_Forms_Uploads::accept(). $raw = $_FILES[ $name ]; $files = self::normalize( $raw ); $allowed = $this->allowed_types( $field ); $max = $this->max_size( $field ); $limit = $this->max_files( $field ); $saved = array(); $errors = array(); $count = 0; foreach ( $files as $file ) { // An empty row shows up when a person picked no file. That is not an error. if ( isset( $file['error'] ) && UPLOAD_ERR_NO_FILE === (int) $file['error'] ) { continue; } ++$count; if ( $count > $limit ) { $errors[] = sprintf( /* translators: %d: how many files are allowed. */ _n( 'Only %d file can be attached.', 'Only %d files can be attached.', $limit, '2ranq-forms' ), $limit ); break; } $result = Ranq_Forms_Uploads::accept( $file, $allowed, $max ); if ( is_wp_error( $result ) ) { $errors[] = $result->get_error_message(); continue; } $saved[] = $result; } // The error travels with the value, so `validate()` only reads it. return array( 'files' => $saved, 'errors' => $errors, ); } /** * Validation. * * @param mixed $value What `sanitize()` returned. * @param array $field The field settings. * * @return string */ public function validate( $value, $field ) { if ( ! empty( $value['errors'] ) ) { return (string) $value['errors'][0]; } if ( ! empty( $field['required'] ) && empty( $value['files'] ) ) { return $this->required_message( $field ); } return ''; } /** * How it is shown in the entry and in the email. * * The ORIGINAL name is shown, while the file on disk carries a random one. * * @param mixed $value The value. * @param array $field The field settings. * * @return string */ public function format_value( $value, $field ) { unset( $field ); if ( empty( $value['files'] ) ) { return ''; } $names = array(); foreach ( $value['files'] as $file ) { $names[] = $file['name'] . ' (' . size_format( (int) $file['size'] ) . ')'; } return implode( ', ', $names ); } /** * For one field with several files PHP builds an array of arrays. This turns * that into a plain list of files, so each one can be handled on its own. * * @param array $raw One row out of `$_FILES`. * * @return array */ private static function normalize( $raw ) { if ( ! isset( $raw['name'] ) ) { return array(); } if ( ! is_array( $raw['name'] ) ) { return array( $raw ); } $files = array(); foreach ( array_keys( $raw['name'] ) as $index ) { $files[] = array( 'name' => isset( $raw['name'][ $index ] ) ? $raw['name'][ $index ] : '', 'type' => isset( $raw['type'][ $index ] ) ? $raw['type'][ $index ] : '', 'tmp_name' => isset( $raw['tmp_name'][ $index ] ) ? $raw['tmp_name'][ $index ] : '', 'error' => isset( $raw['error'][ $index ] ) ? $raw['error'][ $index ] : UPLOAD_ERR_NO_FILE, 'size' => isset( $raw['size'][ $index ] ) ? $raw['size'][ $index ] : 0, ); } return $files; } }