You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
485 lines
16 KiB
485 lines
16 KiB
<?php
|
|
|
|
/**
|
|
* HTML class for a file upload field
|
|
*
|
|
* PHP versions 4 and 5
|
|
*
|
|
* LICENSE: This source file is subject to version 3.01 of the PHP license
|
|
* that is available through the world-wide-web at the following URI:
|
|
* http://www.php.net/license/3_01.txt If you did not receive a copy of
|
|
* the PHP License and are unable to obtain it through the web, please
|
|
* send a note to license@php.net so we can mail you a copy immediately.
|
|
*
|
|
* @category HTML
|
|
* @package HTML_QuickForm
|
|
* @author Adam Daniel <adaniel1@eesus.jnj.com>
|
|
* @author Bertrand Mansion <bmansion@mamasam.com>
|
|
* @author Alexey Borzov <avb@php.net>
|
|
* @copyright 2001-2009 The PHP Group
|
|
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
|
* @version CVS: $Id: file.php,v 1.25 2009/04/04 21:34:02 avb Exp $
|
|
* @link http://pear.php.net/package/HTML_QuickForm
|
|
*/
|
|
|
|
/**
|
|
* HTML class for a file upload field
|
|
*
|
|
* @category HTML
|
|
* @package HTML_QuickForm
|
|
* @author Adam Daniel <adaniel1@eesus.jnj.com>
|
|
* @author Bertrand Mansion <bmansion@mamasam.com>
|
|
* @author Alexey Borzov <avb@php.net>
|
|
* @version Release: 3.2.11
|
|
* @since 1.0
|
|
*/
|
|
class HTML_QuickForm_file extends HTML_QuickForm_input
|
|
{
|
|
/**
|
|
* Uploaded file data, from $_FILES
|
|
* @var array
|
|
*/
|
|
var $_value = null;
|
|
|
|
/**
|
|
* Class constructor
|
|
*
|
|
* @param string Input field name attribute
|
|
* @param string Input field label
|
|
* @param mixed (optional)Either a typical HTML attribute string
|
|
* or an associative array
|
|
* @since 1.0
|
|
* @access public
|
|
*/
|
|
public function __construct($elementName=null, $elementLabel=null, $attributes=null)
|
|
{
|
|
parent::__construct($elementName, $elementLabel, $attributes);
|
|
$this->setType('file');
|
|
}
|
|
|
|
/**
|
|
* Sets size of file element
|
|
*
|
|
* @param int Size of file element
|
|
* @since 1.0
|
|
* @access public
|
|
*/
|
|
function setSize($size)
|
|
{
|
|
$this->updateAttributes(array('size' => $size));
|
|
}
|
|
|
|
/**
|
|
* Returns size of file element
|
|
*
|
|
* @since 1.0
|
|
* @access public
|
|
* @return int
|
|
*/
|
|
function getSize()
|
|
{
|
|
return $this->getAttribute('size');
|
|
}
|
|
|
|
/**
|
|
* Freeze the element so that only its value is returned
|
|
*
|
|
* @access public
|
|
* @return bool
|
|
*/
|
|
function freeze()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Sets value for file element.
|
|
*
|
|
* Actually this does nothing. The function is defined here to override
|
|
* HTML_Quickform_input's behaviour of setting the 'value' attribute. As
|
|
* no sane user-agent uses <input type="file">'s value for anything
|
|
* (because of security implications) we implement file's value as a
|
|
* read-only property with a special meaning.
|
|
*
|
|
* @param mixed Value for file element
|
|
* @since 3.0
|
|
* @access public
|
|
*/
|
|
function setValue($value)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Returns information about the uploaded file
|
|
*
|
|
* @since 3.0
|
|
* @access public
|
|
* @return array
|
|
*/
|
|
public function getValue()
|
|
{
|
|
return $this->_value;
|
|
} // end func getValue
|
|
|
|
// }}}
|
|
// {{{ onQuickFormEvent()
|
|
|
|
/**
|
|
* Called by HTML_QuickForm whenever form event is made on this element
|
|
*
|
|
* @param string Name of event
|
|
* @param mixed event arguments
|
|
* @param object calling object
|
|
* @since 1.0
|
|
* @access public
|
|
* @return bool
|
|
*/
|
|
public function onQuickFormEvent($event, $arg, &$caller)
|
|
{
|
|
switch ($event) {
|
|
case 'updateValue':
|
|
if ($caller->getAttribute('method') == 'get') {
|
|
throw new \Exception('Cannot add a file upload field to a GET method form');
|
|
}
|
|
$this->_value = $this->_findValue();
|
|
$caller->updateAttributes(array('enctype' => 'multipart/form-data'));
|
|
$caller->setMaxFileSize();
|
|
break;
|
|
case 'addElement':
|
|
$this->onQuickFormEvent('createElement', $arg, $caller);
|
|
|
|
return $this->onQuickFormEvent('updateValue', null, $caller);
|
|
break;
|
|
case 'createElement':
|
|
//$className = get_class($this);
|
|
//$this &= new $className($arg[0], $arg[1], $arg[2]);
|
|
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Moves an uploaded file into the destination
|
|
*
|
|
* @param string Destination directory path
|
|
* @param string New file name
|
|
* @access public
|
|
* @return bool Whether the file was moved successfully
|
|
*/
|
|
public function moveUploadedFile($dest, $fileName = '')
|
|
{
|
|
if ($dest != '' && substr($dest, -1) != '/') {
|
|
$dest .= '/';
|
|
}
|
|
$fileName = ($fileName != '') ? $fileName : basename($this->_value['name']);
|
|
return move_uploaded_file($this->_value['tmp_name'], $dest . $fileName);
|
|
}
|
|
|
|
/**
|
|
* Checks if the element contains an uploaded file
|
|
*
|
|
* @access public
|
|
* @return bool true if file has been uploaded, false otherwise
|
|
*/
|
|
public function isUploadedFile()
|
|
{
|
|
return self::_ruleIsUploadedFile($this->_value);
|
|
}
|
|
|
|
/**
|
|
* Checks if the given element contains an uploaded file
|
|
*
|
|
* @param array Uploaded file info (from $_FILES)
|
|
* @access private
|
|
* @return bool true if file has been uploaded, false otherwise
|
|
*/
|
|
public static function _ruleIsUploadedFile($elementValue)
|
|
{
|
|
if ((isset($elementValue['error']) && $elementValue['error'] == 0) ||
|
|
(!empty($elementValue['tmp_name']) && $elementValue['tmp_name'] != 'none')) {
|
|
return is_uploaded_file($elementValue['tmp_name']);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Tries to find the element value from the values array
|
|
*
|
|
* Needs to be redefined here as $_FILES is populated differently from
|
|
* other arrays when element name is of the form foo[bar]
|
|
*
|
|
* @access public
|
|
* @return mixed
|
|
*/
|
|
public function _findValue(&$values = null)
|
|
{
|
|
if (empty($_FILES)) {
|
|
return null;
|
|
}
|
|
$elementName = $this->getName();
|
|
if (isset($_FILES[$elementName])) {
|
|
return $_FILES[$elementName];
|
|
} elseif (false !== ($pos = strpos($elementName, '['))) {
|
|
$base = str_replace(
|
|
array('\\', '\''), array('\\\\', '\\\''),
|
|
substr($elementName, 0, $pos)
|
|
);
|
|
$idx = "['" . str_replace(
|
|
array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
|
|
substr($elementName, $pos + 1, -1)
|
|
) . "']";
|
|
$props = array('name', 'type', 'size', 'tmp_name', 'error');
|
|
$code = "if (!isset(\$_FILES['{$base}']['name']{$idx})) {\n" .
|
|
" return null;\n" .
|
|
"} else {\n" .
|
|
" \$value = array();\n";
|
|
foreach ($props as $prop) {
|
|
$code .= " \$value['{$prop}'] = \$_FILES['{$base}']['{$prop}']{$idx};\n";
|
|
}
|
|
return eval($code . " return \$value;\n}\n");
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getElementJS($param)
|
|
{
|
|
$id = $this->getAttribute('id');
|
|
$ratio = 'aspectRatio: 16 / 9';
|
|
if (!empty($param['ratio'])) {
|
|
$ratio = 'aspectRatio: '.$param['ratio'].',';
|
|
}
|
|
$scalable = 'false';
|
|
if (!empty($param['scalable']) && $param['scalable'] != 'false') {
|
|
$ratio = '';
|
|
$scalable = $param['scalable'];
|
|
}
|
|
|
|
return '<script>
|
|
$(function() {
|
|
var $inputFile = $(\'#'.$id.'\'),
|
|
$image = $(\'#'.$id.'_preview_image\'),
|
|
$input = $(\'[name="'.$id.'_crop_result"]\'),
|
|
$cropButton = $(\'#'.$id.'_crop_button\'),
|
|
$formGroup = $(\'#'.$id.'-form-group\');
|
|
|
|
function isValidType(file) {
|
|
var fileTypes = [\'image/jpg\', \'image/jpeg\', \'image/gif\', \'image/png\'];
|
|
|
|
for(var i = 0; i < fileTypes.length; i++) {
|
|
if(file.type === fileTypes[i]) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function imageCropper() {
|
|
$formGroup.show();
|
|
$cropButton.show();
|
|
|
|
$image
|
|
.cropper(\'destroy\')
|
|
.cropper({
|
|
'.$ratio.'
|
|
responsive : true,
|
|
preview: \'.img-preview\',
|
|
center : false,
|
|
guides : false,
|
|
movable: false,
|
|
zoomable: false,
|
|
rotatable: false,
|
|
scalable: '.$scalable.',
|
|
crop: function(e) {
|
|
// Output the result data for cropping image.
|
|
$input.val(event.detail.x + \',\' + event.detail.y + \',\' + event.detail.width + \',\' + event.detail.height);
|
|
}
|
|
});
|
|
}
|
|
|
|
$inputFile.on(\'change\', function () {
|
|
var inputFile = this,
|
|
file = inputFile.files[0],
|
|
fileReader = new FileReader();
|
|
|
|
$(".img-box").hide();
|
|
$(".img-preview").show();
|
|
|
|
|
|
if (!isValidType(file)) {
|
|
$formGroup.hide();
|
|
$cropButton.hide();
|
|
|
|
if (inputFile.setCustomValidity) {
|
|
inputFile.setCustomValidity(
|
|
inputFile.title ? inputFile.title : \''.get_lang('OnlyImagesAllowed').'\'
|
|
);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (inputFile.setCustomValidity) {
|
|
inputFile.setCustomValidity(\'\');
|
|
}
|
|
|
|
fileReader.readAsDataURL(file);
|
|
fileReader.onload = function () {
|
|
$image
|
|
.attr(\'src\', this.result)
|
|
.on(\'load\', imageCropper);
|
|
};
|
|
});
|
|
|
|
$cropButton.on(\'click\', function () {
|
|
var $imageLarge = $("#image-cut-lg");
|
|
var canvas = $image.cropper(\'getCroppedCanvas\'),
|
|
dataUrl = canvas.toDataURL();
|
|
|
|
$(".img-box").show();
|
|
$(".img-preview").hide();
|
|
|
|
$image.attr(\'src\', dataUrl).cropper(\'destroy\').off(\'load\', imageCropper);
|
|
$imageLarge.attr(\'src\', dataUrl).cropper(\'destroy\').off(\'load\', imageCropper);
|
|
$(\'[name="'.$id.'_crop_image_base_64"]\').val(dataUrl);
|
|
$cropButton.hide();
|
|
});
|
|
});
|
|
</script>';
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function toHtml()
|
|
{
|
|
$js = '';
|
|
if (isset($this->_attributes['crop_image'])) {
|
|
$ratio = '16 / 9';
|
|
if (!empty($this->_attributes['crop_ratio'])) {
|
|
$ratio = $this->_attributes['crop_ratio'];
|
|
}
|
|
$scalable = 'false';
|
|
if (!empty($this->_attributes['crop_scalable'])) {
|
|
$scalable = $this->_attributes['crop_scalable'];
|
|
}
|
|
$js = $this->getElementJS(array('ratio' => $ratio, 'scalable' => $scalable));
|
|
}
|
|
|
|
if ($this->isFrozen()) {
|
|
return $this->getFrozenHtml();
|
|
} else {
|
|
$class = '';
|
|
if (isset($this->_attributes['custom']) && $this->_attributes['custom']) {
|
|
$class = 'input-file';
|
|
}
|
|
|
|
return $js.$this->_getTabs().
|
|
'<input class="'.$class.'" '.$this->_getAttrString($this->_attributes).' />';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $layout
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getTemplate($layout)
|
|
{
|
|
$name = $this->getName();
|
|
$attributes = $this->getAttributes();
|
|
$size = $this->calculateSize();
|
|
|
|
switch ($layout) {
|
|
case FormValidator::LAYOUT_INLINE:
|
|
return '
|
|
<div class="form-group {error_class}">
|
|
<label {label-for} >
|
|
<!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
|
|
{label}
|
|
</label>
|
|
{element}
|
|
</div>';
|
|
break;
|
|
case FormValidator::LAYOUT_HORIZONTAL:
|
|
if (isset($attributes['custom']) && $attributes['custom']) {
|
|
$template = '
|
|
<div class="input-file-container">
|
|
{element}
|
|
<label tabindex="0" {label-for} class="input-file-trigger">
|
|
<i class="fa fa-picture-o fa-lg" aria-hidden="true"></i> {label}
|
|
</label>
|
|
</div>
|
|
<p class="file-return"></p>
|
|
<script>
|
|
document.querySelector("html").classList.add(\'js\');
|
|
var fileInput = document.querySelector( ".input-file" ),
|
|
button = document.querySelector( ".input-file-trigger" ),
|
|
the_return = document.querySelector(".file-return");
|
|
|
|
button.addEventListener("keydown", function(event) {
|
|
if ( event.keyCode == 13 || event.keyCode == 32 ) {
|
|
fileInput.focus();
|
|
}
|
|
});
|
|
button.addEventListener("click", function(event) {
|
|
fileInput.focus();
|
|
return false;
|
|
});
|
|
fileInput.addEventListener("change", function(event) {
|
|
fileName = this.value;
|
|
if (this.files[0]) {
|
|
fileName = this.files[0].name;
|
|
}
|
|
the_return.innerHTML = fileName;
|
|
});
|
|
</script>
|
|
';
|
|
} else {
|
|
$template = '
|
|
<div id="file_'.$name.'" class="form-group row {error_class}">
|
|
|
|
<label {label-for} class="col-sm-'.$size[0].' control-label" >
|
|
<!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
|
|
{label}
|
|
</label>
|
|
<div class="col-sm-'.$size[1].'">
|
|
{icon}
|
|
{element}
|
|
<!-- BEGIN label_2 -->
|
|
<p class="help-block">{label_2}</p>
|
|
<!-- END label_2 -->
|
|
<!-- BEGIN error -->
|
|
<span class="help-inline help-block">{error}</span>
|
|
<!-- END error -->
|
|
</div>
|
|
<div class="col-sm-'.$size[2].'">
|
|
<!-- BEGIN label_3 -->
|
|
{label_3}
|
|
<!-- END label_3 -->
|
|
</div>
|
|
</div>';
|
|
}
|
|
return $template;
|
|
break;
|
|
case FormValidator::LAYOUT_BOX_NO_LABEL:
|
|
return '
|
|
<label {label-for}>{label}</label>
|
|
<div class="input-group">
|
|
|
|
{icon}
|
|
{element}
|
|
</div>';
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|