file.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <?php
  2. /**
  3. * HTML class for a file upload field
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * LICENSE: This source file is subject to version 3.01 of the PHP license
  8. * that is available through the world-wide-web at the following URI:
  9. * http://www.php.net/license/3_01.txt If you did not receive a copy of
  10. * the PHP License and are unable to obtain it through the web, please
  11. * send a note to license@php.net so we can mail you a copy immediately.
  12. *
  13. * @category HTML
  14. * @package HTML_QuickForm
  15. * @author Adam Daniel <adaniel1@eesus.jnj.com>
  16. * @author Bertrand Mansion <bmansion@mamasam.com>
  17. * @author Alexey Borzov <avb@php.net>
  18. * @copyright 2001-2009 The PHP Group
  19. * @license http://www.php.net/license/3_01.txt PHP License 3.01
  20. * @version CVS: $Id: file.php,v 1.25 2009/04/04 21:34:02 avb Exp $
  21. * @link http://pear.php.net/package/HTML_QuickForm
  22. */
  23. /**
  24. * HTML class for a file upload field
  25. *
  26. * @category HTML
  27. * @package HTML_QuickForm
  28. * @author Adam Daniel <adaniel1@eesus.jnj.com>
  29. * @author Bertrand Mansion <bmansion@mamasam.com>
  30. * @author Alexey Borzov <avb@php.net>
  31. * @version Release: 3.2.11
  32. * @since 1.0
  33. */
  34. class HTML_QuickForm_file extends HTML_QuickForm_input
  35. {
  36. /**
  37. * Uploaded file data, from $_FILES
  38. * @var array
  39. */
  40. var $_value = null;
  41. /**
  42. * Class constructor
  43. *
  44. * @param string Input field name attribute
  45. * @param string Input field label
  46. * @param mixed (optional)Either a typical HTML attribute string
  47. * or an associative array
  48. * @since 1.0
  49. * @access public
  50. */
  51. public function __construct($elementName=null, $elementLabel=null, $attributes=null)
  52. {
  53. parent::__construct($elementName, $elementLabel, $attributes);
  54. $this->setType('file');
  55. }
  56. /**
  57. * Sets size of file element
  58. *
  59. * @param int Size of file element
  60. * @since 1.0
  61. * @access public
  62. */
  63. function setSize($size)
  64. {
  65. $this->updateAttributes(array('size' => $size));
  66. }
  67. /**
  68. * Returns size of file element
  69. *
  70. * @since 1.0
  71. * @access public
  72. * @return int
  73. */
  74. function getSize()
  75. {
  76. return $this->getAttribute('size');
  77. }
  78. /**
  79. * Freeze the element so that only its value is returned
  80. *
  81. * @access public
  82. * @return bool
  83. */
  84. function freeze()
  85. {
  86. return false;
  87. }
  88. /**
  89. * Sets value for file element.
  90. *
  91. * Actually this does nothing. The function is defined here to override
  92. * HTML_Quickform_input's behaviour of setting the 'value' attribute. As
  93. * no sane user-agent uses <input type="file">'s value for anything
  94. * (because of security implications) we implement file's value as a
  95. * read-only property with a special meaning.
  96. *
  97. * @param mixed Value for file element
  98. * @since 3.0
  99. * @access public
  100. */
  101. function setValue($value)
  102. {
  103. return null;
  104. }
  105. /**
  106. * Returns information about the uploaded file
  107. *
  108. * @since 3.0
  109. * @access public
  110. * @return array
  111. */
  112. public function getValue()
  113. {
  114. return $this->_value;
  115. } // end func getValue
  116. // }}}
  117. // {{{ onQuickFormEvent()
  118. /**
  119. * Called by HTML_QuickForm whenever form event is made on this element
  120. *
  121. * @param string Name of event
  122. * @param mixed event arguments
  123. * @param object calling object
  124. * @since 1.0
  125. * @access public
  126. * @return bool
  127. */
  128. public function onQuickFormEvent($event, $arg, &$caller)
  129. {
  130. switch ($event) {
  131. case 'updateValue':
  132. if ($caller->getAttribute('method') == 'get') {
  133. throw new \Exception('Cannot add a file upload field to a GET method form');
  134. }
  135. $this->_value = $this->_findValue();
  136. $caller->updateAttributes(array('enctype' => 'multipart/form-data'));
  137. $caller->setMaxFileSize();
  138. break;
  139. case 'addElement':
  140. $this->onQuickFormEvent('createElement', $arg, $caller);
  141. return $this->onQuickFormEvent('updateValue', null, $caller);
  142. break;
  143. case 'createElement':
  144. //$className = get_class($this);
  145. //$this &= new $className($arg[0], $arg[1], $arg[2]);
  146. break;
  147. }
  148. return true;
  149. }
  150. /**
  151. * Moves an uploaded file into the destination
  152. *
  153. * @param string Destination directory path
  154. * @param string New file name
  155. * @access public
  156. * @return bool Whether the file was moved successfully
  157. */
  158. public function moveUploadedFile($dest, $fileName = '')
  159. {
  160. if ($dest != '' && substr($dest, -1) != '/') {
  161. $dest .= '/';
  162. }
  163. $fileName = ($fileName != '') ? $fileName : basename($this->_value['name']);
  164. return move_uploaded_file($this->_value['tmp_name'], $dest . $fileName);
  165. }
  166. /**
  167. * Checks if the element contains an uploaded file
  168. *
  169. * @access public
  170. * @return bool true if file has been uploaded, false otherwise
  171. */
  172. public function isUploadedFile()
  173. {
  174. return self::_ruleIsUploadedFile($this->_value);
  175. }
  176. /**
  177. * Checks if the given element contains an uploaded file
  178. *
  179. * @param array Uploaded file info (from $_FILES)
  180. * @access private
  181. * @return bool true if file has been uploaded, false otherwise
  182. */
  183. public static function _ruleIsUploadedFile($elementValue)
  184. {
  185. if ((isset($elementValue['error']) && $elementValue['error'] == 0) ||
  186. (!empty($elementValue['tmp_name']) && $elementValue['tmp_name'] != 'none')) {
  187. return is_uploaded_file($elementValue['tmp_name']);
  188. } else {
  189. return false;
  190. }
  191. }
  192. /**
  193. * Tries to find the element value from the values array
  194. *
  195. * Needs to be redefined here as $_FILES is populated differently from
  196. * other arrays when element name is of the form foo[bar]
  197. *
  198. * @access public
  199. * @return mixed
  200. */
  201. public function _findValue(&$values = null)
  202. {
  203. if (empty($_FILES)) {
  204. return null;
  205. }
  206. $elementName = $this->getName();
  207. if (isset($_FILES[$elementName])) {
  208. return $_FILES[$elementName];
  209. } elseif (false !== ($pos = strpos($elementName, '['))) {
  210. $base = str_replace(
  211. array('\\', '\''), array('\\\\', '\\\''),
  212. substr($elementName, 0, $pos)
  213. );
  214. $idx = "['" . str_replace(
  215. array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
  216. substr($elementName, $pos + 1, -1)
  217. ) . "']";
  218. $props = array('name', 'type', 'size', 'tmp_name', 'error');
  219. $code = "if (!isset(\$_FILES['{$base}']['name']{$idx})) {\n" .
  220. " return null;\n" .
  221. "} else {\n" .
  222. " \$value = array();\n";
  223. foreach ($props as $prop) {
  224. $code .= " \$value['{$prop}'] = \$_FILES['{$base}']['{$prop}']{$idx};\n";
  225. }
  226. return eval($code . " return \$value;\n}\n");
  227. } else {
  228. return null;
  229. }
  230. }
  231. /**
  232. * @return string
  233. */
  234. public function getElementJS($param)
  235. {
  236. $id = $this->getAttribute('id');
  237. $ratio = 'aspectRatio: 16 / 9';
  238. if (!empty($param['ratio'])) {
  239. $ratio = 'aspectRatio: '.$param['ratio'].',';
  240. }
  241. $scalable = 'false';
  242. if (!empty($param['scalable']) && $param['scalable'] != 'false') {
  243. $ratio = '';
  244. $scalable = $param['scalable'];
  245. }
  246. return '<script>
  247. $(function() {
  248. var $inputFile = $(\'#'.$id.'\'),
  249. $image = $(\'#'.$id.'_preview_image\'),
  250. $input = $(\'[name="'.$id.'_crop_result"]\'),
  251. $cropButton = $(\'#'.$id.'_crop_button\'),
  252. $formGroup = $(\'#'.$id.'-form-group\');
  253. function isValidType(file) {
  254. var fileTypes = [\'image/jpg\', \'image/jpeg\', \'image/gif\', \'image/png\'];
  255. for(var i = 0; i < fileTypes.length; i++) {
  256. if(file.type === fileTypes[i]) {
  257. return true;
  258. }
  259. }
  260. return false;
  261. }
  262. function imageCropper() {
  263. $formGroup.show();
  264. $cropButton.show();
  265. $image
  266. .cropper(\'destroy\')
  267. .cropper({
  268. '.$ratio.'
  269. responsive : true,
  270. preview: \'.img-preview\',
  271. center : false,
  272. guides : false,
  273. movable: false,
  274. zoomable: false,
  275. rotatable: false,
  276. scalable: '.$scalable.',
  277. crop: function(e) {
  278. // Output the result data for cropping image.
  279. $input.val(event.detail.x + \',\' + event.detail.y + \',\' + event.detail.width + \',\' + event.detail.height);
  280. }
  281. });
  282. }
  283. $inputFile.on(\'change\', function () {
  284. var inputFile = this,
  285. file = inputFile.files[0],
  286. fileReader = new FileReader();
  287. $(".img-box").hide();
  288. $(".img-preview").show();
  289. if (!isValidType(file)) {
  290. $formGroup.hide();
  291. $cropButton.hide();
  292. if (inputFile.setCustomValidity) {
  293. inputFile.setCustomValidity(
  294. inputFile.title ? inputFile.title : \''.get_lang('Only PNG, JPG or GIF images allowed').'\'
  295. );
  296. }
  297. return;
  298. }
  299. if (inputFile.setCustomValidity) {
  300. inputFile.setCustomValidity(\'\');
  301. }
  302. fileReader.readAsDataURL(file);
  303. fileReader.onload = function () {
  304. $image
  305. .attr(\'src\', this.result)
  306. .on(\'load\', imageCropper);
  307. };
  308. });
  309. $cropButton.on(\'click\', function () {
  310. var $imageLarge = $("#image-cut-lg");
  311. var canvas = $image.cropper(\'getCroppedCanvas\'),
  312. dataUrl = canvas.toDataURL();
  313. $(".img-box").show();
  314. $(".img-preview").hide();
  315. $image.attr(\'src\', dataUrl).cropper(\'destroy\').off(\'load\', imageCropper);
  316. $imageLarge.attr(\'src\', dataUrl).cropper(\'destroy\').off(\'load\', imageCropper);
  317. $(\'[name="'.$id.'_crop_image_base_64"]\').val(dataUrl);
  318. $cropButton.hide();
  319. });
  320. });
  321. </script>';
  322. }
  323. /**
  324. * @return string
  325. */
  326. public function toHtml()
  327. {
  328. $js = '';
  329. if (isset($this->_attributes['crop_image'])) {
  330. $ratio = '16 / 9';
  331. if (!empty($this->_attributes['crop_ratio'])) {
  332. $ratio = $this->_attributes['crop_ratio'];
  333. }
  334. $scalable = 'false';
  335. if (!empty($this->_attributes['crop_scalable'])) {
  336. $scalable = $this->_attributes['crop_scalable'];
  337. }
  338. $js = $this->getElementJS(array('ratio' => $ratio, 'scalable' => $scalable));
  339. }
  340. if ($this->isFrozen()) {
  341. return $this->getFrozenHtml();
  342. } else {
  343. $class = '';
  344. if (isset($this->_attributes['custom']) && $this->_attributes['custom']) {
  345. $class = 'input-file';
  346. }
  347. return $js.$this->_getTabs().
  348. '<input class="'.$class.'" '.$this->_getAttrString($this->_attributes).' />';
  349. }
  350. }
  351. /**
  352. * @param string $layout
  353. *
  354. * @return string
  355. */
  356. public function getTemplate($layout)
  357. {
  358. $name = $this->getName();
  359. $attributes = $this->getAttributes();
  360. $size = $this->calculateSize();
  361. switch ($layout) {
  362. case FormValidator::LAYOUT_INLINE:
  363. return '
  364. <div class="form-group {error_class}">
  365. <label {label-for} >
  366. <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
  367. {label}
  368. </label>
  369. {element}
  370. </div>';
  371. break;
  372. case FormValidator::LAYOUT_HORIZONTAL:
  373. if (isset($attributes['custom']) && $attributes['custom']) {
  374. $template = '
  375. <div class="input-file-container">
  376. {element}
  377. <label tabindex="0" {label-for} class="input-file-trigger">
  378. <i class="fa fa-picture-o fa-lg" aria-hidden="true"></i> {label}
  379. </label>
  380. </div>
  381. <p class="file-return"></p>
  382. <script>
  383. document.querySelector("html").classList.add(\'js\');
  384. var fileInput = document.querySelector( ".input-file" ),
  385. button = document.querySelector( ".input-file-trigger" ),
  386. the_return = document.querySelector(".file-return");
  387. button.addEventListener("keydown", function(event) {
  388. if ( event.keyCode == 13 || event.keyCode == 32 ) {
  389. fileInput.focus();
  390. }
  391. });
  392. button.addEventListener("click", function(event) {
  393. fileInput.focus();
  394. return false;
  395. });
  396. fileInput.addEventListener("change", function(event) {
  397. fileName = this.value;
  398. if (this.files[0]) {
  399. fileName = this.files[0].name;
  400. }
  401. the_return.innerHTML = fileName;
  402. });
  403. </script>
  404. ';
  405. } else {
  406. $template = '
  407. <div id="file_'.$name.'" class="form-group row {error_class}">
  408. <label {label-for} class="col-sm-'.$size[0].' control-label" >
  409. <!-- BEGIN required --><span class="form_required">*</span><!-- END required -->
  410. {label}
  411. </label>
  412. <div class="col-sm-'.$size[1].'">
  413. {icon}
  414. {element}
  415. <!-- BEGIN label_2 -->
  416. <p class="help-block">{label_2}</p>
  417. <!-- END label_2 -->
  418. <!-- BEGIN error -->
  419. <span class="help-inline help-block">{error}</span>
  420. <!-- END error -->
  421. </div>
  422. <div class="col-sm-'.$size[2].'">
  423. <!-- BEGIN label_3 -->
  424. {label_3}
  425. <!-- END label_3 -->
  426. </div>
  427. </div>';
  428. }
  429. return $template;
  430. break;
  431. case FormValidator::LAYOUT_BOX_NO_LABEL:
  432. return '
  433. <label {label-for}>{label}</label>
  434. <div class="input-group">
  435. {icon}
  436. {element}
  437. </div>';
  438. break;
  439. }
  440. }
  441. }