# Source for file class.upload.php 0.29

Documentation is available at class.upload.php

Webpage is available at http://www.verot.net/php_class_upload.htm

1. <?php
2. // +------------------------------------------------------------------------+
3. // | class.upload.php |
4. // +------------------------------------------------------------------------+
5. // | Copyright (c) Colin Verot 2003-2009. All rights reserved. |
6. // | Version 0.29 |
7. // | Last modified 03/02/2010 |
8. // | Email colin@verot.net |
9. // | Web http://www.verot.net |
10. // +------------------------------------------------------------------------+
11. // | This program is free software; you can redistribute it and/or modify |
12. // | it under the terms of the GNU General Public License version 2 as |
13. // | published by the Free Software Foundation. |
14. // | |
15. // | This program is distributed in the hope that it will be useful, |
16. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18. // | GNU General Public License for more details. |
19. // | |
20. // | You should have received a copy of the GNU General Public License |
21. // | along with this program; if not, write to the |
22. // | Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
23. // | Boston, MA 02111-1307 USA |
24. // | |
25. // | Please give credit on sites that use class.upload and submit changes |
26. // | of the script so other people can use them as well. |
27. // | This script is free to use, don't abuse. |
28. // +------------------------------------------------------------------------+
29. //
31. /**
32. * Class upload
33. *
34. * @version 0.29
35. * @author Colin Verot <colin@verot.net>
36. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
37. * @copyright Colin Verot
38. * @package cmf
39. * @subpackage external
40. */
42. /**
43. * Class upload
44. *
45. * <b>What does it do?</b>
46. *
47. * It manages file uploads for you. In short, it manages the uploaded file,
48. * and allows you to do whatever you want with the file, especially if it
49. * is an image, and as many times as you want.
50. *
51. * It is the ideal class to quickly integrate file upload in your site.
52. * If the file is an image, you can convert, resize, crop it in many ways.
53. * You can also apply filters, add borders, text, watermarks, etc...
54. * That's all you need for a gallery script for instance. Supported formats
55. * are PNG, JPG, GIF and BMP.
56. *
57. * You can also use the class to work on local files, which is especially
58. * useful to use the image manipulation features. The class also supports
59. * Flash uploaders.
60. *
61. * The class works with PHP 4 and 5, and its error messages can
62. * be localized at will.
63. *
64. * <b>How does it work?</b>
65. *
66. * You instanciate the class with the $_FILES['my_field'] array
67. * where my_field is the field name from your upload form.
68. * The class will check if the original file has been uploaded
69. * to its temporary location (alternatively, you can instanciate
70. * the class with a local filename).
71. *
72. * You can then set a number of processing variables to act on the file.
73. * For instance, you can rename the file, and if it is an image,
74. * convert and resize it in many ways.
75. * You can also set what will the class do if the file already exists.
76. *
77. * Then you call the function {@link process} to actually perform the actions
78. * according to the processing parameters you set above.
79. * It will create new instances of the original file,
80. * so the original file remains the same between each process.
81. * The file will be manipulated, and copied to the given location.
82. * The processing variables will be reset once it is done.
83. *
84. * You can repeat setting up a new set of processing variables,
85. * and calling {@link process} again as many times as you want.
86. * When you have finished, you can call {@link clean} to delete
87. * the original uploaded file.
88. *
89. * If you don't set any processing parameters and call {@link process}
90. * just after instanciating the class. The uploaded file will be simply
91. * copied to the given location without any alteration or checks.
92. *
93. * Don't forget to add <i>enctype="multipart/form-data"</i> in your form
94. * tag <form> if you want your form to upload the file.
95. *
96. * <b>How to use it?</b><br>
97. * Create a simple HTML file, with a form such as:
98. * <pre>
99. * <form enctype="multipart/form-data" method="post" action="upload.php">
100. * <input type="file" size="32" name="image_field" value="">
101. * <input type="submit" name="Submit" value="upload">
102. * </form>
103. * </pre>
104. * Create a file called upload.php:
105. * <pre>
106. * $handle = new upload($_FILES['image_field']);
107. * if ($handle->uploaded) {
108. * $handle->file_new_name_body = 'image_resized';
109. * $handle->image_resize = true;
110. * $handle->image_x = 100;
111. * $handle->image_ratio_y = true;
112. * $handle->process('/home/user/files/');
113. * if ($handle->processed) {
114. * echo 'image resized';
115. * $handle->clean();
116. * } else {
117. * echo 'error : ' . $handle->error;
118. * }
119. * }
120. * </pre>
121. *
122. * <b>How to process local files?</b><br>
123. * Use the class as following, the rest being the same as above:
124. * <pre>
125. * $handle = new upload('/home/user/myfile.jpg');
126. * </pre>
127. *
128. * <b>How to set the language?</b><br>
129. * Instantiate the class with a second argument being the language code:
130. * <pre>
131. * $handle = new upload($_FILES['image_field'], 'fr_FR');
132. * $handle = new upload('/home/user/myfile.jpg', 'fr_FR');
133. * </pre>
134. *
135. * <b>How to output the resulting file or picture directly to the browser?</b><br>
136. * Simply call {@link process}() without an argument (or with null as first argument):
137. * <pre>
138. * $handle = new upload($_FILES['image_field']);
139. * header('Content-type: ' . $handle->file_src_mime);
140. * echo $handle->Process();
141. * die();
142. * </pre>
143. * Or if you want to force the download of the file:
144. * <pre>
145. * $handle = new upload($_FILES['image_field']);
146. * header('Content-type: ' . $handle->file_src_mime);
147. * header("Content-Disposition: attachment; filename=".rawurlencode($handle->file_src_name).";");
148. * echo $handle->Process();
149. * die();
150. * </pre>
151. *
152. * <b>Processing parameters</b> (reset after each process)
153. * <ul>
154. * <li><b>file_new_name_body</b> replaces the name body (default: '')<br>
155. * <pre>$handle->file_new_name_body = 'new name';</pre></li>
156. * <li><b>file_name_body_add</b> appends to the name body (default: '')<br>
157. * <pre>$handle->file_name_body_add = '_uploaded';</pre></li>
158. * <li><b>file_name_body_pre</b> prepends to the name body (default: '')<br>
159. * <pre>$handle->file_name_body_pre = 'thumb_';</pre></li>
160. * <li><b>file_new_name_ext</b> replaces the file extension (default: '')<br>
161. * <pre>$handle->file_new_name_ext = 'txt';</pre></li>
162. * <li><b>file_safe_name</b> formats the filename (spaces changed to _) (default: true)<br>
163. * <pre>$handle->file_safe_name = true;</pre></li>
164. * <li><b>file_overwrite</b> sets behaviour if file already exists (default: false)<br>
165. * <pre>$handle->file_overwrite = true;</pre></li>
166. * <li><b>file_auto_rename</b> automatically renames file if it already exists (default: true)<br>
167. * <pre>$handle->file_auto_rename = true;</pre></li>
168. * <li><b>auto_create_dir</b> automatically creates destination directory if missing (default: true)<br>
169. * <pre>$handle->auto_create_dir = true;</pre></li>
170. * <li><b>dir_auto_chmod</b> automatically attempts to chmod the destination directory if not writeable (default: true)<br>
171. * <pre>$handle->dir_auto_chmod = true;</pre></li>
172. * <li><b>dir_chmod</b> chmod used when creating directory or if directory not writeable (default: 0777)<br>
173. * <pre>$handle->dir_chmod = 0777;</pre></li>
174. * <li><b>file_max_size</b> sets maximum upload size (default: upload_max_filesize from php.ini)<br>
175. * <pre>$handle->file_max_size = '1024'; // 1KB</pre></li>
176. * <li><b>mime_check</b> sets if the class check the MIME against the {@link allowed} list (default: true)<br>
177. * <pre>$handle->mime_check = true;</pre></li>
178. * <li><b>no_script</b> sets if the class turns scripts into text files (default: true)<br>
179. * <pre>$handle->no_script = false;</pre></li>
180. * <li><b>allowed</b> array of allowed mime-types. wildcard accepted, as in image/* (default: check {@link Init})<br>
181. * <pre>$handle->allowed = array('application/pdf','application/msword', 'image/*');</pre></li>
182. * <li><b>forbidden</b> array of forbidden mime-types. wildcard accepted, as in image/* (default: check {@link Init})<br>
183. * <pre>$handle->forbidden = array('application/*');</pre></li>
184. * </ul>
185. * <ul>
186. * <li><b>image_convert</b> if set, image will be converted (possible values : ''|'png'|'jpeg'|'gif'|'bmp'; default: '')<br>
187. * <pre>$handle->image_convert = 'jpg';</pre></li>
188. * <li><b>image_background_color</b> if set, will forcibly fill transparent areas with the color, in hexadecimal (default: null)<br>
189. * <pre>$handle->image_background_color = '#FF00FF';</pre></li>
190. * <li><b>image_default_color</b> fallback color background color for non alpha-transparent output formats, such as JPEG or BMP, in hexadecimal (default: #FFFFFF)<br>
191. * <pre>$handle->image_default_color = '#FF00FF';</pre></li>
192. * <li><b>jpeg_quality</b> sets the compression quality for JPEG images (default: 85)<br>
193. * <pre>$handle->jpeg_quality = 50;</pre></li>
194. * <li><b>jpeg_size</b> if set to a size in bytes, will approximate {@link jpeg_quality} so the output image fits within the size (default: null)<br>
195. * <pre>$handle->jpeg_size = 3072;</pre></li>
196. * </ul>
197. * The following eight settings can be used to invalidate an upload if the file is an image (note that <i>open_basedir</i> restrictions prevent the use of these settings)
198. * <ul>
199. * <li><b>image_max_width</b> if set to a dimension in pixels, the upload will be invalid if the image width is greater (default: null)<br>
200. * <pre>$handle->image_max_width = 200;</pre></li>
201. * <li><b>image_max_height</b> if set to a dimension in pixels, the upload will be invalid if the image height is greater (default: null)<br>
202. * <pre>$handle->image_max_height = 100;</pre></li>
203. * <li><b>image_max_pixels</b> if set to a number of pixels, the upload will be invalid if the image number of pixels is greater (default: null)<br>
204. * <pre>$handle->image_max_pixels = 50000;</pre></li>
205. * <li><b>image_max_ratio</b> if set to a aspect ratio (width/height), the upload will be invalid if the image apect ratio is greater (default: null)<br>
206. * <pre>$handle->image_max_ratio = 1.5;</pre></li>
207. * <li><b>image_min_width</b> if set to a dimension in pixels, the upload will be invalid if the image width is lower (default: null)<br>
208. * <pre>$handle->image_min_width = 100;</pre></li>
209. * <li><b>image_min_height</b> if set to a dimension in pixels, the upload will be invalid if the image height is lower (default: null)<br>
210. * <pre>$handle->image_min_height = 500;</pre></li>
211. * <li><b>image_min_pixels</b> if set to a number of pixels, the upload will be invalid if the image number of pixels is lower (default: null)<br>
212. * <pre>$handle->image_min_pixels = 20000;</pre></li>
213. * <li><b>image_min_ratio</b> if set to a aspect ratio (width/height), the upload will be invalid if the image apect ratio is lower (default: null)<br>
214. * <pre>$handle->image_min_ratio = 0.5;</pre></li>
215. * </ul>
216. * <ul>
217. * <li><b>image_resize</b> determines is an image will be resized (default: false)<br>
218. * <pre>$handle->image_resize = true;</pre></li>
219. * </ul>
220. * The following variables are used only if {@link image_resize} == true
221. * <ul>
222. * <li><b>image_x</b> destination image width (default: 150)<br>
223. * <pre>$handle->image_x = 100;</pre></li>
224. * <li><b>image_y</b> destination image height (default: 150)<br>
225. * <pre>$handle->image_y = 200;</pre></li>
226. * </ul>
227. * Use either one of the following
228. * <ul>
229. * <li><b>image_ratio</b> if true, resize image conserving the original sizes ratio, using {@link image_x} AND {@link image_y} as max sizes if true (default: false)<br>
230. * <pre>$handle->image_ratio = true;</pre></li>
231. * <li><b>image_ratio_crop</b> if true, resize image conserving the original sizes ratio, using {@link image_x} AND {@link image_y} as max sizes, and cropping excedent to fill the space. setting can also be a string, with one or more from 'TBLR', indicating which side of the image will be kept while cropping (default: false)<br>
232. * <pre>$handle->image_ratio_crop = true;</pre></li>
233. * <li><b>image_ratio_fill</b> if true, resize image conserving the original sizes ratio, using {@link image_x} AND {@link image_y} as max sizes, fitting the image in the space and coloring the remaining space. setting can also be a string, with one or more from 'TBLR', indicating which side of the space the image will be in (default: false)<br>
234. * <pre>$handle->image_ratio_fill = true;</pre></li>
235. * <li><b>image_ratio_no_zoom_in</b> same as {@link image_ratio}, but won't resize if the source image is smaller than {@link image_x} x {@link image_y} (default: false)<br>
236. * <pre>$handle->image_ratio_no_zoom_in = true;</pre></li>
237. * <li><b>image_ratio_no_zoom_out</b> same as {@link image_ratio}, but won't resize if the source image is bigger than {@link image_x} x {@link image_y} (default: false)<br>
238. * <pre>$handle->image_ratio_no_zoom_out = true;</pre></li>
239. * <li><b>image_ratio_x</b> if true, resize image, calculating {@link image_x} from {@link image_y} and conserving the original sizes ratio (default: false)<br>
240. * <pre>$handle->image_ratio_x = true;</pre></li>
241. * <li><b>image_ratio_y</b> if true, resize image, calculating {@link image_y} from {@link image_x} and conserving the original sizes ratio (default: false)<br>
242. * <pre>$handle->image_ratio_y = true;</pre></li>
243. * <li><b>image_ratio_pixels</b> if set to a long integer, resize image, calculating {@link image_y} and {@link image_x} to match a the number of pixels (default: false)<br>
244. * <pre>$handle->image_ratio_pixels = 25000;</pre></li>
245. * </ul>
246. * The following image manipulations require GD2+
247. * <ul>
248. * <li><b>image_brightness</b> if set, corrects the brightness. value between -127 and 127 (default: null)<br>
249. * <pre>$handle->image_brightness = 40;</pre></li>
250. * <li><b>image_contrast</b> if set, corrects the contrast. value between -127 and 127 (default: null)<br>
251. * <pre>$handle->image_contrast = 50;</pre></li>
252. * <li><b>image_tint_color</b> if set, will tint the image with a color, value as hexadecimal #FFFFFF (default: null)<br>
253. * <pre>$handle->image_tint_color = '#FF0000';</pre></li>
254. * <li><b>image_overlay_color</b> if set, will add a colored overlay, value as hexadecimal #FFFFFF (default: null)<br>
255. * <pre>$handle->image_overlay_color = '#FF0000';</pre></li>
256. * <li><b>image_overlay_percent</b> used when {@link image_overlay_color} is set, determines the opacity (default: 50)<br>
257. * <pre>$handle->image_overlay_percent = 20;</pre></li>
258. * <li><b>image_negative</b> inverts the colors in the image (default: false)<br>
259. * <pre>$handle->image_negative = true;</pre></li>
260. * <li><b>image_greyscale</b> transforms an image into greyscale (default: false)<br>
261. * <pre>$handle->image_greyscale = true;</pre></li>
262. * <li><b>image_threshold</b> applies a threshold filter. value between -127 and 127 (default: null)<br>
263. * <pre>$handle->image_threshold = 20;</pre></li>
264. * </ul>
265. * <ul>
266. * <li><b>image_text</b> creates a text label on the image, value is a string, with eventual replacement tokens (default: null)<br>
267. * <pre>$handle->image_text = 'test';</pre></li>
268. * <li><b>image_text_direction</b> text label direction, either 'h' horizontal or 'v' vertical (default: 'h')<br>
269. * <pre>$handle->image_text_direction = 'v';</pre></li>
270. * <li><b>image_text_color</b> text color for the text label, in hexadecimal (default: #FFFFFF)<br>
271. * <pre>$handle->image_text_color = '#FF0000';</pre></li>
272. * <li><b>image_text_percent</b> text opacity on the text label, integer between 0 and 100 (default: 100)<br>
273. * <pre>$handle->image_text_percent = 50;</pre></li>
274. * <li><b>image_text_background</b> text label background color, in hexadecimal (default: null)<br>
275. * <pre>$handle->image_text_background = '#FFFFFF';</pre></li>
276. * <li><b>image_text_background_percent</b> text label background opacity, integer between 0 and 100 (default: 100)<br>
277. * <pre>$handle->image_text_background_percent = 50;</pre></li>
278. * <li><b>image_text_font</b> built-in font for the text label, from 1 to 5. 1 is the smallest (default: 5)<br>
279. * <pre>$handle->image_text_font = 4;</pre></li>
280. * <li><b>image_text_x</b> absolute text label position, in pixels from the left border. can be negative (default: null)<br>
281. * <pre>$handle->image_text_x = 5;</pre></li>
282. * <li><b>image_text_y</b> absolute text label position, in pixels from the top border. can be negative (default: null)<br>
283. * <pre>$handle->image_text_y = 5;</pre></li>
284. * <li><b>image_text_position</b> text label position withing the image, a combination of one or two from 'TBLR': top, bottom, left, right (default: null)<br>
285. * <pre>$handle->image_text_position = 'LR';</pre></li>
286. * <li><b>image_text_padding</b> text label padding, in pixels. can be overridden by {@link image_text_padding_x} and {@link image_text_padding_y} (default: 0)<br>
287. * <pre>$handle->image_text_padding = 5;</pre></li>
288. * <li><b>image_text_padding_x</b> text label horizontal padding (default: null)<br>
289. * <pre>$handle->image_text_padding_x = 2;</pre></li>
290. * <li><b>image_text_padding_y</b> text label vertical padding (default: null)<br>
291. * <pre>$handle->image_text_padding_y = 10;</pre></li>
292. * <li><b>image_text_alignment</b> text alignment when text has multiple lines, either 'L', 'C' or 'R' (default: 'C')<br>
293. * <pre>$handle->image_text_alignment = 'R';</pre></li>
294. * <li><b>image_text_line_spacing</b> space between lines in pixels, when text has multiple lines (default: 0)<br>
295. * <pre>$handle->image_text_line_spacing = 3;</pre></li>
296. * </ul>
297. * <ul>
298. * <li><b>image_flip</b> flips image, wither 'h' horizontal or 'v' vertical (default: null)<br>
299. * <pre>$handle->image_flip = 'h';</pre></li>
300. * <li><b>image_rotate</b> rotates image. possible values are 90, 180 and 270 (default: null)<br>
301. * <pre>$handle->image_rotate = 90;</pre></li>
302. * <li><b>image_crop</b> crops image. accepts 4, 2 or 1 values as 'T R B L' or 'TB LR' or 'TBLR'. dimension can be 20, or 20px or 20% (default: null)<br>
303. * <pre>$handle->image_crop = array(50,40,30,20); OR '-20 20%'...</pre></li>
304. * <li><b>image_precrop</b> crops image, before an eventual resizing. accepts 4, 2 or 1 values as 'T R B L' or 'TB LR' or 'TBLR'. dimension can be 20, or 20px or 20% (default: null)<br>
305. * <pre>$handle->image_precrop = array(50,40,30,20); OR '-20 20%'...</pre></li>
306. * </ul>
307. * <ul>
308. * <li><b>image_bevel</b> adds a bevel border to the image. value is thickness in pixels (default: null)<br>
309. * <pre>$handle->image_bevel = 20;</pre></li>
310. * <li><b>image_bevel_color1</b> top and left bevel color, in hexadecimal (default: #FFFFFF)<br>
311. * <pre>$handle->image_bevel_color1 = '#FFFFFF';</pre></li>
312. * <li><b>image_bevel_color2</b> bottom and right bevel color, in hexadecimal (default: #000000)<br>
313. * <pre>$handle->image_bevel_color2 = '#000000';</pre></li>
314. * <li><b>image_border</b> adds a unicolor border to the image. accepts 4, 2 or 1 values as 'T R B L' or 'TB LR' or 'TBLR'. dimension can be 20, or 20px or 20% (default: null)<br>
315. * <pre>$handle->image_border = '3px'; OR '-20 20%' OR array(3,2)...</pre></li>
316. * <li><b>image_border_color</b> border color, in hexadecimal (default: #FFFFFF)<br>
317. * <pre>$handle->image_border_color = '#FFFFFF';</pre></li>
318. * <li><b>image_frame</b> type of frame: 1=flat 2=crossed (default: null)<br>
319. * <pre>$handle->image_frame = 2;</pre></li>
320. * <li><b>image_frame_colors</b> list of hex colors, in an array or a space separated string (default: '#FFFFFF #999999 #666666 #000000')<br>
321. * <pre>$handle->image_frame_colors = array('#999999', '#FF0000', '#666666', '#333333', '#000000');</pre></li>
322. * </ul>
323. * <ul>
324. * <li><b>image_watermark</b> adds a watermark on the image, value is a local filename. accepted files are GIF, JPG, BMP, PNG and PNG alpha (default: null)<br>
325. * <pre>$handle->image_watermark = 'watermark.png';</pre></li>
326. * <li><b>image_watermark_x</b> absolute watermark position, in pixels from the left border. can be negative (default: null)<br>
327. * <pre>$handle->image_watermark_x = 5;</pre></li>
328. * <li><b>image_watermark_y</b> absolute watermark position, in pixels from the top border. can be negative (default: null)<br>
329. * <pre>$handle->image_watermark_y = 5;</pre></li>
330. * <li><b>image_watermark_position</b> watermark position withing the image, a combination of one or two from 'TBLR': top, bottom, left, right (default: null)<br>
331. * <pre>$handle->image_watermark_position = 'LR';</pre></li>
332. * </ul>
333. * <ul>
334. * <li><b>image_reflection_height</b> if set, a reflection will be added. Format is either in pixels or percentage, such as 40, '40', '40px' or '40%' (default: null)<br>
335. * <pre>$handle->image_reflection_height = '25%';</pre></li>
336. * <li><b>image_reflection_space</b> space in pixels between the source image and the reflection, can be negative (default: null)<br>
337. * <pre>$handle->image_reflection_space = 3;</pre></li>
338. * <li><b>image_reflection_color</b> reflection background color, in hexadecimal. Now deprecated in favor of {@link image_default_color} (default: #FFFFFF)<br>
339. * <pre>$handle->image_default_color = '#000000';</pre></li>
340. * <li><b>image_reflection_opacity</b> opacity level at which the reflection starts, integer between 0 and 100 (default: 60)<br>
341. * <pre>$handle->image_reflection_opacity = 60;</pre></li>
342. * </ul>
343. *
344. * <b>Values that can be read before calling {@link process}()</b>
345. * <ul>
346. * <li><b>file_src_name</b> Source file name</li>
347. * <li><b>file_src_name_body</b> Source file name body</li>
348. * <li><b>file_src_name_ext</b> Source file extension</li>
349. * <li><b>file_src_pathname</b> Source file complete path and name</li>
350. * <li><b>file_src_mime</b> Source file mime type</li>
351. * <li><b>file_src_size</b> Source file size in bytes</li>
352. * <li><b>file_src_error</b> Upload error code</li>
353. * <li><b>file_is_image</b> Boolean flag, true if the file is a supported image type</li>
354. * </ul>
355. * If the file is a supported image type (and <i>open_basedir</i> restrictions allow it)
356. * <ul>
357. * <li><b>image_src_x</b> Source file width in pixels</li>
358. * <li><b>image_src_y</b> Source file height in pixels</li>
359. * <li><b>image_src_pixels</b> Source file number of pixels</li>
360. * <li><b>image_src_type</b> Source file type (png, jpg, gif or bmp)</li>
361. * <li><b>image_src_bits</b> Source file color depth</li>
362. * </ul>
363. *
364. * <b>Values that can be read after calling {@link process}()</b>
365. * <ul>
366. * <li><b>file_dst_path</b> Destination file path</li>
367. * <li><b>file_dst_name_body</b> Destination file name body</li>
368. * <li><b>file_dst_name_ext</b> Destination file extension</li>
369. * <li><b>file_dst_name</b> Destination file name</li>
370. * <li><b>file_dst_pathname</b> Destination file complete path and name</li>
371. * </ul>
372. * If the file is a supported image type
373. * <ul>
374. * <li><b>image_dst_x</b> Destination file width</li>
375. * <li><b>image_dst_y</b> Destination file height</li>
376. * <li><b>image_convert</b> Destination file format</li>
377. * </ul>
378. *
379. * <b>Requirements</b>
380. *
381. * Most of the image operations require GD. GD2 is greatly recommended
382. *
383. * The class is compatible with PHP 4.3+, and compatible with PHP5
384. *
385. * <b>Changelog</b>
386. * <ul>
387. * <li><b>v 0.29</b> 03/02/2010<br>
388. * - added protection against malicious images<br>
389. * - added zip and torrent MIME type<br>
390. * - replaced split() with explode()<br>
391. * - initialise image_dst_x/y with image_src_x/y<br>
392. * - removed {@link mime_fileinfo}, {@link mime_file}, {@link mime_magic} and {@link mime_getimagesize} from the docs since they are used before {@link process}<br>
393. * - added more extensions and MIME types<br>
394. * - improved MIME type validation<br>
395. * - improved logging</li>
396. * <li><b>v 0.28</b> 10/08/2009<br>
397. * - replaced ereg functions to be compatible with PHP 5.3<br>
398. * - added flv MIME type<br>
399. * - improved MIME type detection<br>
400. * - added {@link file_name_body_pre} to prepend a string to the file name<br>
401. * - added {@link mime_fileinfo}, {@link mime_file}, {@link mime_magic} and {@link mime_getimagesize} so that it is possible to deactivate some MIME type checking method<br>
402. * - use exec() rather than shell_exec(), to play better with safe mode <br>
403. * - added some error messages<br>
404. * - fix bug when checking on conditions, {@link processed} wasn't propagated properly</li>
405. * <li><b>v 0.27</b> 14/05/2009<br>
406. * - look for the language files directory from __FILE__<br>
407. * - deactivate {@link file_auto_rename} if {@link file_overwrite} is set<br>
408. * - improved transparency replacement for true color images<br>
409. * - fixed calls to newer version of UNIX file utility<br>
410. * - fixed error when using PECL Fileinfo extension in SAFE MODE, and when using the finfo class<br>
411. * - added {@link image_precrop} to crop the image before an eventual resizing</li>
412. * <li><b>v 0.26</b> 13/11/2008<br>
413. * - rewrote conversion from palette to true color to handle transparency better<br>
414. * - fixed imagecopymergealpha() when the overlayed image is of wrong dimensions<br>
415. * - fixed imagecreatenew() when the image to create have less than 1 pixels width or height<br>
416. * - rewrote MIME type detection to be more secure and not rely on browser information; now using Fileinfo PECL extension, UNIX file() command, MIME magic, and getimagesize(), in that order<br>
417. * - added support for Flash uploaders<br>
418. * - some bug fixing and error handling</li>
419. * <li><b>v 0.25</b> 17/11/2007<br>
420. * - added translation files and mechanism to instantiate the class with a language different from English<br>
421. * - added {@link forbidden} to set an array of forbidden MIME types<br>
422. * - implemented support for simple wildcards in {@link allowed} and {@link forbidden}, such as image/*<br>
423. * - preset the file extension to the desired conversion format when converting an image<br>
424. * - added read and write support for BMP images<br>
425. * - added a flag {@link file_is_image} to determine if the file is a supported image type<br>
426. * - the class now provides some information about the image, before calling {@link process}(). Available are {@link image_src_x}, {@link image_src_y} and the newly introduced {@link image_src_bits}, {@link image_src_pixels} and {@link image_src_type}. Note that this will not work if <i>open_basedir</i> restrictions are in place<br>
427. * - improved logging; now provides useful system information<br>
428. * - added some more pre-processing checks for files that are images: {@link image_max_width}, {@link image_max_height}, {@link image_max_pixels}, {@link image_max_ratio}, {@link image_min_width}, {@link image_min_height}, {@link image_min_pixels} and {@link image_min_ratio}<br>
429. * - added {@link image_ratio_pixels} to resize an image to a number of pixels, keeping aspect ratio<br>
430. * - added {@link image_is_palette} and {@link image_is_transparent} and {@link image_transparent_color} for GIF images<br>
431. * - added {@link image_default_color} to define a fallback color for non alpha-transparent output formats, such as JPEG or BMP<br>
432. * - changed {@link image_background_color}, which now forces transparent areas to be painted<br>
433. * - improved reflections and color overlays so that it works with alpha transparent images<br>
434. * - {@link image_reflection_color} is now deprecated in favour of {@link image_default_color}<br />
435. * - transparent PNGs are now processed in true color, and fully preserving the alpha channel when doing merges<br>
436. * - transparent GIFs are now automatically detected. {@link preserve_transparency} is deprecated<br>
437. * - transparent true color images can be saved as GIF while retaining transparency, semi transparent areas being merged with {@link image_default_color}<br>
438. * - transparent true color images can be saved as JPG/BMP with the semi transparent areas being merged with {@link image_default_color}<br>
439. * - fixed conversion of images to true color<br>
440. * - the class can now output the uploaded files content as the return value of process() if the function is called with an empty or null argumenti, or no argument</li>
441. * <li><b>v 0.24</b> 25/05/2007<br>
442. * - added {@link image_background_color}, to set the default background color of an image<br>
443. * - added possibility of using replacement tokens in text labels<br>
444. * - changed default JPEG quality to 85<br>
445. * - fixed a small bug when using greyscale filter and associated filters<br>
446. * - added {@link image_ratio_fill} in order to fit an image within some dimensions and color the remaining space. Very similar to {@link image_ratio_crop}<br>
447. * - improved the recursive creation of directories<br>
448. * - the class now converts palette based images to true colors before doing graphic manipulations</li>
449. * <li><b>v 0.23</b> 23/12/2006<br>
450. * - fixed a bug when processing more than once the same uploaded file. If there is an open_basedir restriction, the class now creates a temporary file for the first call to process(). This file will be used for subsequent processes, and will be deleted upon calling clean()</li>
451. * <li><b>v 0.22</b> 16/12/2006<br>
452. * - added automatic creation of a temporary file if the upload directory is not within open_basedir<br>
453. * - fixed a bug which was preventing to work on a local file by overwriting it with its processed copy<br>
454. * - added MIME types video/x-ms-wmv and image/x-png and fixed PNG support for IE weird MIME types<br>
455. * - modified {@link image_ratio_crop} so it can accept one or more from string 'TBLR', determining which side of the image is kept while cropping<br>
456. * - added support for multiple lines in the text, using "\n" as a line break<br>
457. * - added {@link image_text_line_spacing} which allow to set the space between several lines of text<br>
458. * - added {@link image_text_alignment} which allow to set the alignment when text has several lines<br>
459. * - {@link image_text_font} can now be set to the path of a GDF font to load external fonts<br>
460. * - added {@link image_reflection_height} to create a reflection of the source image, which height is in pixels or percentage<br>
461. * - added {@link image_reflection_space} to set the space in pixels between the source image and the reflection<br>
462. * - added {@link image_reflection_color} to set the reflection background color<br>
463. * - added {@link image_reflection_opacity} to set the initial level of opacity of the reflection</li>
464. * <li><b>v 0.21</b> 30/09/2006<br>
465. * - added {@link image_ratio_crop} which resizes within {@link image_x} and {@link image_y}, keeping ratio, but filling the space by cropping excedent of image<br>
466. * - added {@link mime_check}, which default is true, to set checks against {@link allowed} MIME list<br>
467. * - if MIME is empty, the class now triggers an error<br>
468. * - color #000000 is OK for {@link image_text_color}, and related text transparency bug fixed<br>
469. * - {@link gd_version}() now uses gd_info(), or else phpinfo()<br>
470. * - fixed path issue when the destination path has no trailing slash on Windows systems <br>
471. * - removed inline functions to be fully PHP5 compatible </li>
472. * <li><b>v 0.20</b> 11/08/2006<br>
473. * - added some more error checking and messages (GD presence, permissions...)<br>
474. * - fix when uploading files without extension<br>
475. * - changed values for {@link image_brightness} and {@link image_contrast} to be between -127 and 127<br>
476. * - added {@link dir_auto_create} to automatically and recursively create destination directory if missing.<br>
477. * - added {@link dir_auto_chmod} to automatically chmod the destination directory if not writeable.<br>
478. * - added {@link dir_chmod} to set the default chmod to use.<br>
479. * - added {@link image_crop} to crop images<br>
480. * - added {@link image_negative} to invert the colors on the image<br>
481. * - added {@link image_greyscale} to turn the image into greyscale<br>
482. * - added {@link image_threshold} to apply a threshold filter on the image<br>
483. * - added {@link image_bevel}, {@link image_bevel_color1} and {@link image_bevel_color2} to add a bevel border<br>
484. * - added {@link image_border} and {@link image_border_color} to add a single color border<br>
485. * - added {@link image_frame} and {@link image_frame_colors} to add a multicolored frame</li>
486. * <li><b>v 0.19</b> 29/03/2006<br>
487. * - class is now compatible i18n (thanks Sylwester).<br>
488. * - the class can mow manipulate local files, not only uploaded files (instanciate the class with a local filename).<br>
489. * - {@link file_safe_name} has been improved a bit.<br>
490. * - added {@link image_brightness}, {@link image_contrast}, {@link image_tint_color}, {@link image_overlay_color} and {@link image_overlay_percent} to do color manipulation on the images.<br>
491. * - added {@link image_text} and all derivated settings to add a text label on the image.<br>
492. * - added {@link image_watermark} and all derivated settings to add a watermark image on the image.<br>
493. * - added {@link image_flip} and {@link image_rotate} for more image manipulations<br>
494. * - added {@link jpeg_size} to calculate the JPG compression quality in order to fit within one filesize.</li>
495. * <li><b>v 0.18</b> 02/02/2006<br>
496. * - added {@link no_script} to turn dangerous scripts into text files.<br>
497. * - added {@link mime_magic_check} to set the class to use mime_magic.<br>
498. * - added {@link preserve_transparency} *experimental*. Thanks Gregor.<br>
499. * - fixed size and mime checking, wasn't working :/ Thanks Willem.<br>
500. * - fixed memory leak when resizing images.<br>
501. * - when resizing, it is not necessary anymore to set {@link image_convert}.<br>
502. * - il is now possible to simply convert an image, with no resizing.<br>
503. * - sets the default {@link file_max_size} to upload_max_filesize from php.ini. Thanks Edward</li>
504. * <li><b>v 0.17</b> 28/05/2005<br>
505. * - the class can be used with any version of GD.<br>
506. * - added security check on the file with a list of mime-types.<br>
507. * - changed the license to GPL v2 only</li>
508. * <li><b>v 0.16</b> 19/05/2005<br>
509. * - added {@link file_auto_rename} automatic file renaming if the same filename already exists.<br>
510. * - added {@link file_safe_name} safe formatting of the filename (spaces to _underscores so far).<br>
511. * - added some more error reporting to avoid crash if GD is not present</li>
512. * <li><b>v 0.15</b> 16/04/2005<br>
513. * - added JPEG compression quality setting. Thanks Vad</li>
514. * <li><b>v 0.14</b> 14/03/2005<br>
515. * - reworked the class file to allow parsing with phpDocumentor</li>
516. * <li><b>v 0.13</b> 07/03/2005<br>
517. * - fixed a bug with {@link image_ratio}. Thanks Justin.<br>
518. * - added {@link image_ratio_no_zoom_in} and {@link image_ratio_no_zoom_out} </li>
519. * <li><b>v 0.12</b> 21/01/2005<br>
520. * - added {@link image_ratio} to resize within max values, keeping image ratio</li>
521. * <li><b>v 0.11</b> 22/08/2003<br>
522. * - update for GD2 (changed imageresized() into imagecopyresampled() and imagecreate() into imagecreatetruecolor())</li>
523. * </ul>
524. *
525. * @package cmf
526. * @subpackage external
527. */
528. class upload {
531. /**
532. * Class version
533. *
534. * @access public
535. * @var string
536. */
537. var $version;
539. /**
540. * Uploaded file name
541. *
542. * @access public
543. * @var string
544. */
545. var $file_src_name;
547. /**
548. * Uploaded file name body (i.e. without extension)
549. *
550. * @access public
551. * @var string
552. */
553. var $file_src_name_body;
555. /**
556. * Uploaded file name extension
557. *
558. * @access public
559. * @var string
560. */
561. var $file_src_name_ext;
563. /**
564. * Uploaded file MIME type
565. *
566. * @access public
567. * @var string
568. */
569. var $file_src_mime;
571. /**
572. * Uploaded file size, in bytes
573. *
574. * @access public
575. * @var double
576. */
577. var $file_src_size;
579. /**
580. * Holds eventual PHP error code from $_FILES
581. *
582. * @access public
583. * @var string
584. */
585. var $file_src_error;
587. /**
588. * Uloaded file name, including server path
589. *
590. * @access private
591. * @var string
592. */
593. var $file_src_pathname;
595. /**
596. * Uloaded file name temporary copy
597. *
598. * @access private
599. * @var string
600. */
601. var $file_src_temp;
603. /**
604. * Destination file name
605. *
606. * @access private
607. * @var string
608. */
609. var $file_dst_path;
611. /**
612. * Destination file name
613. *
614. * @access public
615. * @var string
616. */
617. var $file_dst_name;
619. /**
620. * Destination file name body (i.e. without extension)
621. *
622. * @access public
623. * @var string
624. */
625. var $file_dst_name_body;
627. /**
628. * Destination file extension
629. *
630. * @access public
631. * @var string
632. */
633. var $file_dst_name_ext;
635. /**
636. * Destination file name, including path
637. *
638. * @access private
639. * @var string
640. */
641. var $file_dst_pathname;
643. /**
644. * Source image width
645. *
646. * @access private
647. * @var integer
648. */
649. var $image_src_x;
651. /**
652. * Source image height
653. *
654. * @access private
655. * @var integer
656. */
657. var $image_src_y;
659. /**
660. * Source image color depth
661. *
662. * @access private
663. * @var integer
664. */
665. var $image_src_bits;
667. /**
668. * Number of pixels
669. *
670. * @access private
671. * @var long
672. */
673. var $image_src_pixels;
675. /**
676. * Type of image (png, gif, jpg or bmp)
677. *
678. * @access private
679. * @var string
680. */
681. var $image_src_type;
683. /**
684. * Destination image width
685. *
686. * @access private
687. * @var integer
688. */
689. var $image_dst_x;
691. /**
692. * Destination image height
693. *
694. * @access private
695. * @var integer
696. */
697. var $image_dst_y;
699. /**
700. * Supported image formats
701. *
702. * @access private
703. * @var array
704. */
705. var $image_supported;
707. /**
708. * Flag to determine if the source file is an image
709. *
710. * @access private
711. * @var boolean
712. */
713. var $file_is_image;
715. /**
716. * Flag set after instanciating the class
717. *
718. * Indicates if the file has been uploaded properly
719. *
720. * @access public
721. * @var bool
722. */
723. var $uploaded;
725. /**
726. * Flag stopping PHP upload checks
727. *
728. * Indicates whether we instanciated the class with a filename, in which case
729. * we will not check on the validity of the PHP *upload*
730. *
731. * This flag is automatically set to true when working on a local file
732. *
733. * Warning: for uploads, this flag MUST be set to false for security reason
734. *
735. * @access public
736. * @var bool
737. */
738. var $no_upload_check;
740. /**
741. * Flag set after calling a process
742. *
743. * Indicates if the processing, and copy of the resulting file went OK
744. *
745. * @access public
746. * @var bool
747. */
748. var $processed;
750. /**
751. * Holds eventual error message in plain english
752. *
753. * @access public
754. * @var string
755. */
756. var $error;
758. /**
759. * Holds an HTML formatted log
760. *
761. * @access public
762. * @var string
763. */
764. var $log;
767. // overiddable processing variables
770. /**
771. * Set this variable to replace the name body (i.e. without extension)
772. *
773. * @access public
774. * @var string
775. */
776. var $file_new_name_body;
778. /**
779. * Set this variable to append a string to the file name body
780. *
781. * @access public
782. * @var string
783. */
784. var $file_name_body_add;
786. /**
787. * Set this variable to prepend a string to the file name body
788. *
789. * @access public
790. * @var string
791. */
792. var $file_name_body_pre;
794. /**
795. * Set this variable to change the file extension
796. *
797. * @access public
798. * @var string
799. */
800. var $file_new_name_ext;
802. /**
803. * Set this variable to format the filename (spaces changed to _)
804. *
805. * @access public
806. * @var boolean
807. */
808. var $file_safe_name;
810. /**
811. * Set this variable to false if you don't want to check the MIME against the allowed list
812. *
813. * This variable is set to true by default for security reason
814. *
815. * @access public
816. * @var boolean
817. */
818. var $mime_check;
820. /**
821. * Set this variable to false if you don't want to check the MIME with Fileinfo PECL extension
822. *
823. * You can also set it with the path of the magic database file.
824. * If set to true, the class will try to read the MAGIC environment variable
825. * and if it is empty, will default to '/usr/share/file/magic'
826. * If set to an empty string, it will call finfo_open without the path argument
827. *
828. * This variable is set to true by default for security reason
829. *
830. * @access public
831. * @var boolean
832. */
833. var $mime_fileinfo;
835. /**
836. * Set this variable to false if you don't want to check the MIME with UNIX file() command
837. *
838. * This variable is set to true by default for security reason
839. *
840. * @access public
841. * @var boolean
842. */
843. var $mime_file;
845. /**
846. * Set this variable to false if you don't want to check the MIME with the magic.mime file
847. *
848. * The function mime_content_type() will be deprecated,
849. * and this variable will be set to false in a future release
850. *
851. * This variable is set to true by default for security reason
852. *
853. * @access public
854. * @var boolean
855. */
856. var $mime_magic;
858. /**
859. * Set this variable to false if you don't want to check the MIME with getimagesize()
860. *
861. * The class tries to get a MIME type from getimagesize()
862. * If no MIME is returned, it tries to guess the MIME type from the file type
863. *
864. * This variable is set to true by default for security reason
865. *
866. * @access public
867. * @var boolean
868. */
869. var $mime_getimagesize;
871. /**
872. * Set this variable to false if you don't want to turn dangerous scripts into simple text files
873. *
874. * @access public
875. * @var boolean
876. */
877. var $no_script;
879. /**
880. * Set this variable to true to allow automatic renaming of the file
881. * if the file already exists
882. *
883. * Default value is true
884. *
885. * For instance, on uploading foo.ext,<br>
886. * if foo.ext already exists, upload will be renamed foo_1.ext<br>
887. * and if foo_1.ext already exists, upload will be renamed foo_2.ext<br>
888. *
889. * Note that this option doesn't have any effect if {@link file_overwrite} is true
890. *
891. * @access public
892. * @var bool
893. */
894. var $file_auto_rename;
896. /**
897. * Set this variable to true to allow automatic creation of the destination
898. * directory if it is missing (works recursively)
899. *
900. * Default value is true
901. *
902. * @access public
903. * @var bool
904. */
905. var $dir_auto_create;
907. /**
908. * Set this variable to true to allow automatic chmod of the destination
909. * directory if it is not writeable
910. *
911. * Default value is true
912. *
913. * @access public
914. * @var bool
915. */
916. var $dir_auto_chmod;
918. /**
919. * Set this variable to the default chmod you want the class to use
920. * when creating directories, or attempting to write in a directory
921. *
922. * Default value is 0777 (without quotes)
923. *
924. * @access public
925. * @var bool
926. */
927. var $dir_chmod;
929. /**
930. * Set this variable tu true to allow overwriting of an existing file
931. *
932. * Default value is false, so no files will be overwritten
933. *
934. * @access public
935. * @var bool
936. */
937. var $file_overwrite;
939. /**
940. * Set this variable to change the maximum size in bytes for an uploaded file
941. *
942. * Default value is the value <i>upload_max_filesize</i> from php.ini
943. *
944. * @access public
945. * @var double
946. */
947. var $file_max_size;
949. /**
950. * Set this variable to true to resize the file if it is an image
951. *
952. * You will probably want to set {@link image_x} and {@link image_y}, and maybe one of the ratio variables
953. *
954. * Default value is false (no resizing)
955. *
956. * @access public
957. * @var bool
958. */
959. var $image_resize;
961. /**
962. * Set this variable to convert the file if it is an image
963. *
964. * Possibles values are : ''; 'png'; 'jpeg'; 'gif'; 'bmp'
965. *
966. * Default value is '' (no conversion)<br>
967. * If {@link resize} is true, {@link convert} will be set to the source file extension
968. *
969. * @access public
970. * @var string
971. */
972. var $image_convert;
974. /**
975. * Set this variable to the wanted (or maximum/minimum) width for the processed image, in pixels
976. *
977. * Default value is 150
978. *
979. * @access public
980. * @var integer
981. */
982. var $image_x;
984. /**
985. * Set this variable to the wanted (or maximum/minimum) height for the processed image, in pixels
986. *
987. * Default value is 150
988. *
989. * @access public
990. * @var integer
991. */
992. var $image_y;
994. /**
995. * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}
996. *
997. * Default value is false
998. *
999. * @access public
1000. * @var bool
1001. */
1002. var $image_ratio;
1004. /**
1005. * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}
1006. *
1007. * The image will be resized as to fill the whole space, and excedent will be cropped
1008. *
1009. * Value can also be a string, one or more character from 'TBLR' (top, bottom, left and right)
1010. * If set as a string, it determines which side of the image is kept while cropping.
1011. * By default, the part of the image kept is in the center, i.e. it crops equally on both sides
1012. *
1013. * Default value is false
1014. *
1015. * @access public
1016. * @var mixed
1017. */
1018. var $image_ratio_crop;
1020. /**
1021. * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y}
1022. *
1023. * The image will be resized to fit entirely in the space, and the rest will be colored.
1024. * The default color is white, but can be set with {@link image_default_color}
1025. *
1026. * Value can also be a string, one or more character from 'TBLR' (top, bottom, left and right)
1027. * If set as a string, it determines in which side of the space the image is displayed.
1028. * By default, the image is displayed in the center, i.e. it fills the remaining space equally on both sides
1029. *
1030. * Default value is false
1031. *
1032. * @access public
1033. * @var mixed
1034. */
1035. var $image_ratio_fill;
1037. /**
1038. * Set this variable to a number of pixels so that {@link image_x} and {@link image_y} are the best match possible
1039. *
1040. * The image will be resized to have approximatively the number of pixels
1041. * The aspect ratio wil be conserved
1042. *
1043. * Default value is false
1044. *
1045. * @access public
1046. * @var mixed
1047. */
1048. var $image_ratio_pixels;
1050. /**
1051. * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y},
1052. * but only if original image is bigger
1053. *
1054. * Default value is false
1055. *
1056. * @access public
1057. * @var bool
1058. */
1059. var $image_ratio_no_zoom_in;
1061. /**
1062. * Set this variable to keep the original size ratio to fit within {@link image_x} x {@link image_y},
1063. * but only if original image is smaller
1064. *
1065. * Default value is false
1066. *
1067. * @access public
1068. * @var bool
1069. */
1070. var $image_ratio_no_zoom_out;
1072. /**
1073. * Set this variable to calculate {@link image_x} automatically , using {@link image_y} and conserving ratio
1074. *
1075. * Default value is false
1076. *
1077. * @access public
1078. * @var bool
1079. */
1080. var $image_ratio_x;
1082. /**
1083. * Set this variable to calculate {@link image_y} automatically , using {@link image_x} and conserving ratio
1084. *
1085. * Default value is false
1086. *
1087. * @access public
1088. * @var bool
1089. */
1090. var $image_ratio_y;
1092. /**
1093. * Set this variable to set a maximum image width, above which the upload will be invalid
1094. *
1095. * Default value is null
1096. *
1097. * @access public
1098. * @var integer
1099. */
1100. var $image_max_width;
1102. /**
1103. * Set this variable to set a maximum image height, above which the upload will be invalid
1104. *
1105. * Default value is null
1106. *
1107. * @access public
1108. * @var integer
1109. */
1110. var $image_max_height;
1112. /**
1113. * Set this variable to set a maximum number of pixels for an image, above which the upload will be invalid
1114. *
1115. * Default value is null
1116. *
1117. * @access public
1118. * @var long
1119. */
1120. var $image_max_pixels;
1122. /**
1123. * Set this variable to set a maximum image aspect ratio, above which the upload will be invalid
1124. *
1125. * Note that ratio = width / height
1126. *
1127. * Default value is null
1128. *
1129. * @access public
1130. * @var float
1131. */
1132. var $image_max_ratio;
1134. /**
1135. * Set this variable to set a minimum image width, below which the upload will be invalid
1136. *
1137. * Default value is null
1138. *
1139. * @access public
1140. * @var integer
1141. */
1142. var $image_min_width;
1144. /**
1145. * Set this variable to set a minimum image height, below which the upload will be invalid
1146. *
1147. * Default value is null
1148. *
1149. * @access public
1150. * @var integer
1151. */
1152. var $image_min_height;
1154. /**
1155. * Set this variable to set a minimum number of pixels for an image, below which the upload will be invalid
1156. *
1157. * Default value is null
1158. *
1159. * @access public
1160. * @var long
1161. */
1162. var $image_min_pixels;
1164. /**
1165. * Set this variable to set a minimum image aspect ratio, below which the upload will be invalid
1166. *
1167. * Note that ratio = width / height
1168. *
1169. * Default value is null
1170. *
1171. * @access public
1172. * @var float
1173. */
1174. var $image_min_ratio;
1176. /**
1177. * Quality of JPEG created/converted destination image
1178. *
1179. * Default value is 85
1180. *
1181. * @access public
1182. * @var integer
1183. */
1184. var $jpeg_quality;
1186. /**
1187. * Determines the quality of the JPG image to fit a desired file size
1188. *
1189. * Value is in bytes. The JPG quality will be set between 1 and 100%
1190. * The calculations are approximations.
1191. *
1192. * Default value is null (no calculations)
1193. *
1194. * @access public
1195. * @var integer
1196. */
1197. var $jpeg_size;
1199. /**
1200. * Preserve transparency when resizing or converting an image (deprecated)
1201. *
1202. * Default value is automatically set to true for transparent GIFs
1203. * This setting is now deprecated
1204. *
1205. * @access public
1206. * @var integer
1207. */
1208. var $preserve_transparency;
1210. /**
1211. * Flag set to true when the image is transparent
1212. *
1213. * This is actually used only for transparent GIFs
1214. *
1215. * @access public
1216. * @var boolean
1217. */
1218. var $image_is_transparent;
1220. /**
1221. * Transparent color in a palette
1222. *
1223. * This is actually used only for transparent GIFs
1224. *
1225. * @access public
1226. * @var boolean
1227. */
1228. var $image_transparent_color;
1230. /**
1231. * Background color, used to paint transparent areas with
1232. *
1233. * If set, it will forcibly remove transparency by painting transparent areas with the color
1234. * This setting will fill in all transparent areas in PNG and GIF, as opposed to {@link image_default_color}
1235. * which will do so only in BMP, JPEG, and alpha transparent areas in transparent GIFs
1236. * This setting overrides {@link image_default_color}
1237. *
1238. * Default value is null
1239. *
1240. * @access public
1241. * @var string
1242. */
1243. var $image_background_color;
1245. /**
1246. * Default color for non alpha-transparent images
1247. *
1248. * This setting is to be used to define a background color for semi transparent areas
1249. * of an alpha transparent when the output format doesn't support alpha transparency
1250. * This is useful when, from an alpha transparent PNG image, or an image with alpha transparent features
1251. * if you want to output it as a transparent GIFs for instance, you can set a blending color for transparent areas
1252. * If you output in JPEG or BMP, this color will be used to fill in the previously transparent areas
1253. *
1254. * The default color white
1255. *
1256. * @access public
1257. * @var boolean
1258. */
1259. var $image_default_color;
1261. /**
1262. * Flag set to true when the image is not true color
1263. *
1264. * @access public
1265. * @var boolean
1266. */
1267. var $image_is_palette;
1269. /**
1270. * Corrects the image brightness
1271. *
1272. * Value can range between -127 and 127
1273. *
1274. * Default value is null
1275. *
1276. * @access public
1277. * @var integer
1278. */
1279. var $image_brightness;
1281. /**
1282. * Corrects the image contrast
1283. *
1284. * Value can range between -127 and 127
1285. *
1286. * Default value is null
1287. *
1288. * @access public
1289. * @var integer
1290. */
1291. var $image_contrast;
1293. /**
1294. * Applies threshold filter
1295. *
1296. * Value can range between -127 and 127
1297. *
1298. * Default value is null
1299. *
1300. * @access public
1301. * @var integer
1302. */
1303. var $image_threshold;
1305. /**
1306. * Applies a tint on the image
1307. *
1308. * Value is an hexadecimal color, such as #FFFFFF
1309. *
1310. * Default value is null
1311. *
1312. * @access public
1313. * @var string;
1314. */
1315. var $image_tint_color;
1317. /**
1318. * Applies a colored overlay on the image
1319. *
1320. * Value is an hexadecimal color, such as #FFFFFF
1321. *
1322. * To use with {@link image_overlay_percent}
1323. *
1324. * Default value is null
1325. *
1326. * @access public
1327. * @var string;
1328. */
1329. var $image_overlay_color;
1331. /**
1332. * Sets the percentage for the colored overlay
1333. *
1334. * Value is a percentage, as an integer between 0 and 100
1335. *
1336. * Unless used with {@link image_overlay_color}, this setting has no effect
1337. *
1338. * Default value is 50
1339. *
1340. * @access public
1341. * @var integer
1342. */
1343. var $image_overlay_percent;
1345. /**
1346. * Inverts the color of an image
1347. *
1348. * Default value is FALSE
1349. *
1350. * @access public
1351. * @var boolean;
1352. */
1353. var $image_negative;
1355. /**
1356. * Turns the image into greyscale
1357. *
1358. * Default value is FALSE
1359. *
1360. * @access public
1361. * @var boolean;
1362. */
1363. var $image_greyscale;
1365. /**
1366. * Adds a text label on the image
1367. *
1368. * Value is a string, any text. Text will not word-wrap, although you can use breaklines in your text "\n"
1369. *
1370. * If set, this setting allow the use of all other settings starting with image_text_
1371. *
1372. * Replacement tokens can be used in the string:
1373. * <pre>
1374. * gd_version src_name src_name_body src_name_ext
1375. * src_pathname src_mime src_x src_y
1376. * src_type src_bits src_pixels
1377. * src_size src_size_kb src_size_mb src_size_human
1378. * dst_path dst_name_body dst_pathname
1379. * dst_name dst_name_ext dst_x dst_y
1380. * date time host server ip
1381. * </pre>
1382. * The tokens must be enclosed in square brackets: [dst_x] will be replaced by the width of the picture
1383. *
1384. * Default value is null
1385. *
1386. * @access public
1387. * @var string;
1388. */
1389. var $image_text;
1391. /**
1392. * Sets the text direction for the text label
1393. *
1394. * Value is either 'h' or 'v', as in horizontal and vertical
1395. *
1396. * Default value is h (horizontal)
1397. *
1398. * @access public
1399. * @var string;
1400. */
1401. var $image_text_direction;
1403. /**
1404. * Sets the text color for the text label
1405. *
1406. * Value is an hexadecimal color, such as #FFFFFF
1407. *
1408. * Default value is #FFFFFF (white)
1409. *
1410. * @access public
1411. * @var string;
1412. */
1413. var $image_text_color;
1415. /**
1416. * Sets the text visibility in the text label
1417. *
1418. * Value is a percentage, as an integer between 0 and 100
1419. *
1420. * Default value is 100
1421. *
1422. * @access public
1423. * @var integer
1424. */
1425. var $image_text_percent;
1427. /**
1428. * Sets the text background color for the text label
1429. *
1430. * Value is an hexadecimal color, such as #FFFFFF
1431. *
1432. * Default value is null (no background)
1433. *
1434. * @access public
1435. * @var string;
1436. */
1437. var $image_text_background;
1439. /**
1440. * Sets the text background visibility in the text label
1441. *
1442. * Value is a percentage, as an integer between 0 and 100
1443. *
1444. * Default value is 100
1445. *
1446. * @access public
1447. * @var integer
1448. */
1449. var $image_text_background_percent;
1451. /**
1452. * Sets the text font in the text label
1453. *
1454. * Value is a an integer between 1 and 5 for GD built-in fonts. 1 is the smallest font, 5 the biggest
1455. * Value can also be a string, which represents the path to a GDF font. The font will be loaded into GD, and used as a built-in font.
1456. *
1457. * Default value is 5
1458. *
1459. * @access public
1460. * @var mixed;
1461. */
1462. var $image_text_font;
1464. /**
1465. * Sets the text label position within the image
1466. *
1467. * Value is one or two out of 'TBLR' (top, bottom, left, right)
1468. *
1469. * The positions are as following:
1470. * <pre>
1471. * TL T TR
1472. * L R
1473. * BL B BR
1474. * </pre>
1475. *
1476. * Default value is null (centered, horizontal and vertical)
1477. *
1478. * Note that is {@link image_text_x} and {@link image_text_y} are used, this setting has no effect
1479. *
1480. * @access public
1481. * @var string;
1482. */
1483. var $image_text_position;
1485. /**
1486. * Sets the text label absolute X position within the image
1487. *
1488. * Value is in pixels, representing the distance between the left of the image and the label
1489. * If a negative value is used, it will represent the distance between the right of the image and the label
1490. *
1491. * Default value is null (so {@link image_text_position} is used)
1492. *
1493. * @access public
1494. * @var integer
1495. */
1496. var $image_text_x;
1498. /**
1499. * Sets the text label absolute Y position within the image
1500. *
1501. * Value is in pixels, representing the distance between the top of the image and the label
1502. * If a negative value is used, it will represent the distance between the bottom of the image and the label
1503. *
1504. * Default value is null (so {@link image_text_position} is used)
1505. *
1506. * @access public
1507. * @var integer
1508. */
1509. var $image_text_y;
1511. /**
1512. * Sets the text label padding
1513. *
1514. * Value is in pixels, representing the distance between the text and the label background border
1515. *
1516. * Default value is 0
1517. *
1518. * This setting can be overriden by {@link image_text_padding_x} and {@link image_text_padding_y}
1519. *
1520. * @access public
1521. * @var integer
1522. */
1523. var $image_text_padding;
1525. /**
1526. * Sets the text label horizontal padding
1527. *
1528. * Value is in pixels, representing the distance between the text and the left and right label background borders
1529. *
1530. * Default value is null
1531. *
1532. * If set, this setting overrides the horizontal part of {@link image_text_padding}
1533. *
1534. * @access public
1535. * @var integer
1536. */
1537. var $image_text_padding_x;
1539. /**
1540. * Sets the text label vertical padding
1541. *
1542. * Value is in pixels, representing the distance between the text and the top and bottom label background borders
1543. *
1544. * Default value is null
1545. *
1546. * If set, his setting overrides the vertical part of {@link image_text_padding}
1547. *
1548. * @access public
1549. * @var integer
1550. */
1551. var $image_text_padding_y;
1553. /**
1554. * Sets the text alignment
1555. *
1556. * Value is a string, which can be either 'L', 'C' or 'R'
1557. *
1558. * Default value is 'C'
1559. *
1560. * This setting is relevant only if the text has several lines.
1561. *
1562. * @access public
1563. * @var string;
1564. */
1565. var $image_text_alignment;
1567. /**
1568. * Sets the text line spacing
1569. *
1570. * Value is an integer, in pixels
1571. *
1572. * Default value is 0
1573. *
1574. * This setting is relevant only if the text has several lines.
1575. *
1576. * @access public
1577. * @var integer
1578. */
1579. var $image_text_line_spacing;
1581. /**
1582. * Sets the height of the reflection
1583. *
1584. * Value is an integer in pixels, or a string which format can be in pixels or percentage.
1585. * For instance, values can be : 40, '40', '40px' or '40%'
1586. *
1587. * Default value is null, no reflection
1588. *
1589. * @access public
1590. * @var mixed;
1591. */
1592. var $image_reflection_height;
1594. /**
1595. * Sets the space between the source image and its relection
1596. *
1597. * Value is an integer in pixels, which can be negative
1598. *
1599. * Default value is 2
1600. *
1601. * This setting is relevant only if {@link image_reflection_height} is set
1602. *
1603. * @access public
1604. * @var integer
1605. */
1606. var $image_reflection_space;
1608. /**
1609. * Sets the color of the reflection background (deprecated)
1610. *
1611. * Value is an hexadecimal color, such as #FFFFFF
1612. *
1613. * Default value is #FFFFFF
1614. *
1615. * This setting is relevant only if {@link image_reflection_height} is set
1616. *
1617. * This setting is now deprecated in favor of {@link image_default_color}
1618. *
1619. * @access public
1620. * @var string;
1621. */
1622. var $image_reflection_color;
1624. /**
1625. * Sets the initial opacity of the reflection
1626. *
1627. * Value is an integer between 0 (no opacity) and 100 (full opacity).
1628. * The reflection will start from {@link image_reflection_opacity} and end up at 0
1629. *
1630. * Default value is 60
1631. *
1632. * This setting is relevant only if {@link image_reflection_height} is set
1633. *
1634. * @access public
1635. * @var integer
1636. */
1637. var $image_reflection_opacity;
1639. /**
1640. * Flips the image vertically or horizontally
1641. *
1642. * Value is either 'h' or 'v', as in horizontal and vertical
1643. *
1644. * Default value is null (no flip)
1645. *
1646. * @access public
1647. * @var string;
1648. */
1649. var $image_flip;
1651. /**
1652. * Rotates the image by increments of 45 degrees
1653. *
1654. * Value is either 90, 180 or 270
1655. *
1656. * Default value is null (no rotation)
1657. *
1658. * @access public
1659. * @var string;
1660. */
1661. var $image_rotate;
1663. /**
1664. * Crops an image
1665. *
1666. * Values are four dimensions, or two, or one (CSS style)
1667. * They represent the amount cropped top, right, bottom and left.
1668. * These values can either be in an array, or a space separated string.
1669. * Each value can be in pixels (with or without 'px'), or percentage (of the source image)
1670. *
1671. * For instance, are valid:
1672. * <pre>
1673. * $foo->image_crop = 20 OR array(20);
1674. * $foo->image_crop = '20px' OR array('20px');
1675. * $foo->image_crop = '20 40' OR array('20', 40);
1676. * $foo->image_crop = '-20 25%' OR array(-20, '25%');
1677. * $foo->image_crop = '20px 25%' OR array('20px', '25%');
1678. * $foo->image_crop = '20% 25%' OR array('20%', '25%');
1679. * $foo->image_crop = '20% 25% 10% 30%' OR array('20%', '25%', '10%', '30%');
1680. * $foo->image_crop = '20px 25px 2px 2px' OR array('20px', '25%px', '2px', '2px');
1681. * $foo->image_crop = '20 25% 40px 10%' OR array(20, '25%', '40px', '10%');
1682. * </pre>
1683. *
1684. * If a value is negative, the image will be expanded, and the extra parts will be filled with black
1685. *
1686. * Default value is null (no cropping)
1687. *
1688. * @access public
1689. * @var string OR array;
1690. */
1691. var $image_crop;
1693. /**
1694. * Crops an image, before an eventual resizing
1695. *
1696. * See {@link image_crop} for valid formats
1697. *
1698. * Default value is null (no cropping)
1699. *
1700. * @access public
1701. * @var string OR array;
1702. */
1703. var $image_precrop;
1705. /**
1706. * Adds a bevel border on the image
1707. *
1708. * Value is a positive integer, representing the thickness of the bevel
1709. *
1710. * If the bevel colors are the same as the background, it makes a fade out effect
1711. *
1712. * Default value is null (no bevel)
1713. *
1714. * @access public
1715. * @var integer
1716. */
1717. var $image_bevel;
1719. /**
1720. * Top and left bevel color
1721. *
1722. * Value is a color, in hexadecimal format
1723. * This setting is used only if {@link image_bevel} is set
1724. *
1725. * Default value is #FFFFFF
1726. *
1727. * @access public
1728. * @var string;
1729. */
1730. var $image_bevel_color1;
1732. /**
1733. * Right and bottom bevel color
1734. *
1735. * Value is a color, in hexadecimal format
1736. * This setting is used only if {@link image_bevel} is set
1737. *
1738. * Default value is #000000
1739. *
1740. * @access public
1741. * @var string;
1742. */
1743. var $image_bevel_color2;
1745. /**
1746. * Adds a single-color border on the outer of the image
1747. *
1748. * Values are four dimensions, or two, or one (CSS style)
1749. * They represent the border thickness top, right, bottom and left.
1750. * These values can either be in an array, or a space separated string.
1751. * Each value can be in pixels (with or without 'px'), or percentage (of the source image)
1752. *
1753. * See {@link image_crop} for valid formats
1754. *
1755. * If a value is negative, the image will be cropped.
1756. * Note that the dimensions of the picture will be increased by the borders' thickness
1757. *
1758. * Default value is null (no border)
1759. *
1760. * @access public
1761. * @var integer
1762. */
1763. var $image_border;
1765. /**
1766. * Border color
1767. *
1768. * Value is a color, in hexadecimal format.
1769. * This setting is used only if {@link image_border} is set
1770. *
1771. * Default value is #FFFFFF
1772. *
1773. * @access public
1774. * @var string;
1775. */
1776. var $image_border_color;
1778. /**
1779. * Adds a multi-color frame on the outer of the image
1780. *
1781. * Value is an integer. Two values are possible for now:
1782. * 1 for flat border, meaning that the frame is mirrored horizontally and vertically
1783. * 2 for crossed border, meaning that the frame will be inversed, as in a bevel effect
1784. *
1785. * The frame will be composed of colored lines set in {@link image_frame_colors}
1786. *
1787. * Note that the dimensions of the picture will be increased by the borders' thickness
1788. *
1789. * Default value is null (no frame)
1790. *
1791. * @access public
1792. * @var integer
1793. */
1794. var $image_frame;
1796. /**
1797. * Sets the colors used to draw a frame
1798. *
1799. * Values is a list of n colors in hexadecimal format.
1800. * These values can either be in an array, or a space separated string.
1801. *
1802. * The colors are listed in the following order: from the outset of the image to its center
1803. *
1804. * For instance, are valid:
1805. * <pre>
1806. * $foo->image_frame_colors = '#FFFFFF #999999 #666666 #000000';
1807. * $foo->image_frame_colors = array('#FFFFFF', '#999999', '#666666', '#000000');
1808. * </pre>
1809. *
1810. * This setting is used only if {@link image_frame} is set
1811. *
1812. * Default value is '#FFFFFF #999999 #666666 #000000'
1813. *
1814. * @access public
1815. * @var string OR array;
1816. */
1817. var $image_frame_colors;
1819. /**
1820. * Adds a watermark on the image
1821. *
1822. * Value is a local image filename, relative or absolute. GIF, JPG, BMP and PNG are supported, as well as PNG alpha.
1823. *
1824. * If set, this setting allow the use of all other settings starting with image_watermark_
1825. *
1826. * Default value is null
1827. *
1828. * @access public
1829. * @var string;
1830. */
1831. var $image_watermark;
1833. /**
1834. * Sets the watermarkposition within the image
1835. *
1836. * Value is one or two out of 'TBLR' (top, bottom, left, right)
1837. *
1838. * The positions are as following: TL T TR
1839. * L R
1840. * BL B BR
1841. *
1842. * Default value is null (centered, horizontal and vertical)
1843. *
1844. * Note that is {@link image_watermark_x} and {@link image_watermark_y} are used, this setting has no effect
1845. *
1846. * @access public
1847. * @var string;
1848. */
1849. var $image_watermark_position;
1851. /**
1852. * Sets the watermark absolute X position within the image
1853. *
1854. * Value is in pixels, representing the distance between the top of the image and the watermark
1855. * If a negative value is used, it will represent the distance between the bottom of the image and the watermark
1856. *
1857. * Default value is null (so {@link image_watermark_position} is used)
1858. *
1859. * @access public
1860. * @var integer
1861. */
1862. var $image_watermark_x;
1864. /**
1865. * Sets the twatermark absolute Y position within the image
1866. *
1867. * Value is in pixels, representing the distance between the left of the image and the watermark
1868. * If a negative value is used, it will represent the distance between the right of the image and the watermark
1869. *
1870. * Default value is null (so {@link image_watermark_position} is used)
1871. *
1872. * @access public
1873. * @var integer
1874. */
1875. var $image_watermark_y;
1877. /**
1878. * Allowed MIME types
1879. *
1880. * Default is a selection of safe mime-types, but you might want to change it
1881. *
1882. * Simple wildcards are allowed, such as image/* or application/*
1883. *
1884. * @access public
1885. * @var array
1886. */
1887. var $allowed;
1889. /**
1890. * Forbidden MIME types
1891. *
1892. * Default is a selection of safe mime-types, but you might want to change it
1893. * To only check for forbidden MIME types, and allow everything else, set {@link allowed} to array('* / *') without the spaces
1894. *
1895. * Simple wildcards are allowed, such as image/* or application/*
1896. *
1897. * @access public
1898. * @var array
1899. */
1900. var $forbidden;
1902. /**
1903. * Array of translated error messages
1904. *
1905. * By default, the language is english (en_GB)
1906. * Translations can be in separate files, in a lang/ subdirectory
1907. *
1908. * @access public
1909. * @var array
1910. */
1911. var $translation;
1913. /**
1914. * Language selected for the translations
1915. *
1916. * By default, the language is english ("en_GB")
1917. *
1918. * @access public
1919. * @var array
1920. */
1921. var $language;
1923. /**
1924. * Init or re-init all the processing variables to their default values
1925. *
1926. * This function is called in the constructor, and after each call of {@link process}
1927. *
1928. * @access private
1929. */
1930. function init() {
1932. // overiddable variables
1933. $this->file_new_name_body = ''; // replace the name body
1934. $this->file_name_body_add = ''; // append to the name body
1935. $this->file_name_body_pre = ''; // prepend to the name body
1936. $this->file_new_name_ext = ''; // replace the file extension
1937. $this->file_safe_name = true; // format safely the filename
1938. $this->file_overwrite = false; // allows overwritting if the file already exists
1939. $this->file_auto_rename = true; // auto-rename if the file already exists
1940. $this->dir_auto_create = true; // auto-creates directory if missing
1941. $this->dir_auto_chmod = true; // auto-chmod directory if not writeable
1942. $this->dir_chmod = 0777; // default chmod to use
1944. $this->mime_check = true; // checks the mime type against the allowed list
1945. $this->mime_fileinfo = true; // MIME detection with Fileinfo PECL extension
1946. $this->mime_file = true; // MIME detection with UNIX file() command
1947. $this->mime_magic = true; // MIME detection with mime_magic (mime_content_type())
1948. $this->mime_getimagesize = true; // MIME detection with getimagesize()
1949. $this->no_script = true; // turns scripts into test files
1951. $val = trim(ini_get('upload_max_filesize'));
1952. $last = strtolower($val{strlen($val)-1});
1953. switch($last) {
1954. case 'g':
1955. $val *= 1024;
1956. case 'm':
1957. $val *= 1024;
1958. case 'k':
1959. $val *= 1024;
1960. }
1961. $this->file_max_size = $val;
1963. $this->image_resize = false; // resize the image
1964. $this->image_convert = ''; // convert. values :''; 'png'; 'jpeg'; 'gif'; 'bmp'
1966. $this->image_x = 150;
1967. $this->image_y = 150;
1968. $this->image_ratio = false; // keeps aspect ratio with x and y dimensions
1969. $this->image_ratio_crop = false; // keeps aspect ratio with x and y dimensions, filling the space
1970. $this->image_ratio_fill = false; // keeps aspect ratio with x and y dimensions, fitting the image in the space, and coloring the rest
1971. $this->image_ratio_pixels = false; // keeps aspect ratio, calculating x and y so that the image is approx the set number of pixels
1972. $this->image_ratio_no_zoom_in = false;
1973. $this->image_ratio_no_zoom_out = false;
1974. $this->image_ratio_x = false; // calculate the $image_x if true
1975. $this->image_ratio_y = false; // calculate the $image_y if true
1976. $this->jpeg_quality = 85;
1977. $this->jpeg_size = null;
1978. $this->preserve_transparency = false;
1979. $this->image_is_transparent = false;
1980. $this->image_transparent_color = null;
1981. $this->image_background_color = null;
1982. $this->image_default_color = '#ffffff';
1983. $this->image_is_palette = false;
1985. $this->image_max_width = null;
1986. $this->image_max_height = null;
1987. $this->image_max_pixels = null;
1988. $this->image_max_ratio = null;
1989. $this->image_min_width = null;
1990. $this->image_min_height = null;
1991. $this->image_min_pixels = null;
1992. $this->image_min_ratio = null;
1994. $this->image_brightness = null;
1995. $this->image_contrast = null;
1996. $this->image_threshold = null;
1997. $this->image_tint_color = null;
1998. $this->image_overlay_color = null;
1999. $this->image_overlay_percent = null;
2000. $this->image_negative = false;
2001. $this->image_greyscale = false;
2003. $this->image_text = null;
2004. $this->image_text_direction = null;
2005. $this->image_text_color = '#FFFFFF';
2006. $this->image_text_percent = 100;
2007. $this->image_text_background = null;
2008. $this->image_text_background_percent = 100;
2009. $this->image_text_font = 5;
2010. $this->image_text_x = null;
2011. $this->image_text_y = null;
2012. $this->image_text_position = null;
2013. $this->image_text_padding = 0;
2014. $this->image_text_padding_x = null;
2015. $this->image_text_padding_y = null;
2016. $this->image_text_alignment = 'C';
2017. $this->image_text_line_spacing = 0;
2019. $this->image_reflection_height = null;
2020. $this->image_reflection_space = 2;
2021. $this->image_reflection_color = '#ffffff';
2022. $this->image_reflection_opacity = 60;
2024. $this->image_watermark = null;
2025. $this->image_watermark_x = null;
2026. $this->image_watermark_y = null;
2027. $this->image_watermark_position = null;
2029. $this->image_flip = null;
2030. $this->image_rotate = null;
2031. $this->image_crop = null;
2032. $this->image_precrop = null;
2034. $this->image_bevel = null;
2035. $this->image_bevel_color1 = '#FFFFFF';
2036. $this->image_bevel_color2 = '#000000';
2037. $this->image_border = null;
2038. $this->image_border_color = '#FFFFFF';
2039. $this->image_frame = null;
2040. $this->image_frame_colors = '#FFFFFF #999999 #666666 #000000';
2042. $this->forbidden = array();
2043. $this->allowed = array("application/arj",
2044. "application/excel",
2045. "application/gnutar",
2046. "application/mspowerpoint",
2047. "application/msword",
2048. "application/octet-stream",
2049. "application/onenote",
2050. "application/pdf",
2051. "application/plain",
2052. "application/postscript",
2053. "application/powerpoint",
2054. "application/rar",
2055. "application/rtf",
2056. "application/vnd.ms-excel",
2057. "application/vnd.ms-excel.addin.macroEnabled.12",
2058. "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
2059. "application/vnd.ms-excel.sheet.macroEnabled.12",
2060. "application/vnd.ms-excel.template.macroEnabled.12",
2061. "application/vnd.ms-office",
2062. "application/vnd.ms-officetheme",
2063. "application/vnd.ms-powerpoint",
2064. "application/vnd.ms-powerpoint.addin.macroEnabled.12",
2065. "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
2066. "application/vnd.ms-powerpoint.slide.macroEnabled.12",
2067. "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
2068. "application/vnd.ms-powerpoint.template.macroEnabled.12",
2069. "application/vnd.ms-word",
2070. "application/vnd.ms-word.document.macroEnabled.12",
2071. "application/vnd.ms-word.template.macroEnabled.12",
2072. "application/vnd.oasis.opendocument.chart",
2073. "application/vnd.oasis.opendocument.database",
2074. "application/vnd.oasis.opendocument.formula",
2075. "application/vnd.oasis.opendocument.graphics",
2076. "application/vnd.oasis.opendocument.graphics-template",
2077. "application/vnd.oasis.opendocument.image",
2078. "application/vnd.oasis.opendocument.presentation",
2079. "application/vnd.oasis.opendocument.presentation-template",
2080. "application/vnd.oasis.opendocument.spreadsheet",
2081. "application/vnd.oasis.opendocument.spreadsheet-template",
2082. "application/vnd.oasis.opendocument.text",
2083. "application/vnd.oasis.opendocument.text-master",
2084. "application/vnd.oasis.opendocument.text-template",
2085. "application/vnd.oasis.opendocument.text-web",
2086. "application/vnd.openofficeorg.extension",
2087. "application/vnd.openxmlformats-officedocument.presentationml.presentation",
2088. "application/vnd.openxmlformats-officedocument.presentationml.slide",
2089. "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
2090. "application/vnd.openxmlformats-officedocument.presentationml.template",
2091. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
2092. "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
2093. "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2094. "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2095. "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
2096. "application/vocaltec-media-file",
2097. "application/wordperfect",
2098. "application/x-bittorrent",
2099. "application/x-bzip",
2100. "application/x-bzip2",
2101. "application/x-compressed",
2102. "application/x-excel",
2103. "application/x-gzip",
2104. "application/x-latex",
2105. "application/x-midi",
2106. "application/xml",
2107. "application/x-msexcel",
2108. "application/x-rar-compressed",
2109. "application/x-rtf",
2110. "application/x-shockwave-flash",
2111. "application/x-sit",
2112. "application/x-stuffit",
2113. "application/x-troff-msvideo",
2114. "application/x-zip",
2115. "application/x-zip-compressed",
2116. "application/zip",
2117. "audio/*",
2118. "image/*",
2119. "multipart/x-gzip",
2120. "multipart/x-zip",
2121. "text/plain",
2122. "text/richtext",
2123. "text/xml",
2124. "video/*");
2126. }
2128. /**
2129. * Constructor. Checks if the file has been uploaded
2130. *
2131. * The constructor takes $_FILES['form_field'] array as argument
2132. * where form_field is the form field name
2133. *
2134. * The constructor will check if the file has been uploaded in its temporary location, and
2135. * accordingly will set {@link uploaded} (and {@link error} is an error occurred)
2136. *
2137. * If the file has been uploaded, the constructor will populate all the variables holding the upload
2138. * information (none of the processing class variables are used here).
2139. * You can have access to information about the file (name, size, MIME type...).
2140. *
2141. *
2142. * Alternatively, you can set the first argument to be a local filename (string)
2143. * This allows processing of a local file, as if the file was uploaded
2144. *
2145. * The optional second argument allows you to set the language for the error messages
2146. *
2147. * @access private
2148. * @param array $file $_FILES['form_field']
2149. * or string $file Local filename
2150. * @param string $lang Optional language code
2151. */
2152. function upload($file, $lang = 'en_GB') {
2154. $this->version = '0.29';
2156. $this->file_src_name = '';
2157. $this->file_src_name_body = '';
2158. $this->file_src_name_ext = '';
2159. $this->file_src_mime = '';
2160. $this->file_src_size = '';
2161. $this->file_src_error = '';
2162. $this->file_src_pathname = '';
2163. $this->file_src_temp = '';
2165. $this->file_dst_path = '';
2166. $this->file_dst_name = '';
2167. $this->file_dst_name_body = '';
2168. $this->file_dst_name_ext = '';
2169. $this->file_dst_pathname = '';
2171. $this->image_src_x = null;
2172. $this->image_src_y = null;
2173. $this->image_src_bits = null;
2174. $this->image_src_type = null;
2175. $this->image_src_pixels = null;
2176. $this->image_dst_x = 0;
2177. $this->image_dst_y = 0;
2179. $this->uploaded = true;
2180. $this->no_upload_check = false;
2181. $this->processed = true;
2182. $this->error = '';
2183. $this->log = '';
2184. $this->allowed = array();
2185. $this->forbidden = array();
2186. $this->file_is_image = false;
2187. $this->init();
2188. $info = null;
2189. $mime_from_browser = null;
2191. // sets default language
2192. $this->translation = array();
2193. $this->translation['file_error'] = 'File error. Please try again.';
2194. $this->translation['local_file_missing'] = 'Local file doesn\'t exist.';
2195. $this->translation['local_file_not_readable'] = 'Local file is not readable.';
2196. $this->translation['uploaded_too_big_ini'] = 'File upload error (the uploaded file exceeds the upload_max_filesize directive in php.ini).';
2197. $this->translation['uploaded_too_big_html'] = 'File upload error (the uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form).';
2198. $this->translation['uploaded_partial'] = 'File upload error (the uploaded file was only partially uploaded).';
2199. $this->translation['uploaded_missing'] = 'File upload error (no file was uploaded).';
2200. $this->translation['uploaded_no_tmp_dir'] = 'File upload error (missing a temporary folder).';
2201. $this->translation['uploaded_cant_write'] = 'File upload error (failed to write file to disk).';
2202. $this->translation['uploaded_err_extension'] = 'File upload error (file upload stopped by extension).';
2203. $this->translation['uploaded_unknown'] = 'File upload error (unknown error code).';
2204. $this->translation['try_again'] = 'File upload error. Please try again.';
2205. $this->translation['file_too_big'] = 'File too big.';
2206. $this->translation['no_mime'] = 'MIME type can\'t be detected.';
2207. $this->translation['incorrect_file'] = 'Incorrect type of file.';
2208. $this->translation['image_too_wide'] = 'Image too wide.';
2209. $this->translation['image_too_narrow'] = 'Image too narrow.';
2210. $this->translation['image_too_high'] = 'Image too high.';
2211. $this->translation['image_too_short'] = 'Image too short.';
2212. $this->translation['ratio_too_high'] = 'Image ratio too high (image too wide).';
2213. $this->translation['ratio_too_low'] = 'Image ratio too low (image too high).';
2214. $this->translation['too_many_pixels'] = 'Image has too many pixels.';
2215. $this->translation['not_enough_pixels'] = 'Image has not enough pixels.';
2216. $this->translation['file_not_uploaded'] = 'File not uploaded. Can\'t carry on a process.';
2217. $this->translation['already_exists'] = '%s already exists. Please change the file name.';
2218. $this->translation['temp_file_missing'] = 'No correct temp source file. Can\'t carry on a process.';
2219. $this->translation['source_missing'] = 'No correct uploaded source file. Can\'t carry on a process.';
2220. $this->translation['destination_dir'] = 'Destination directory can\'t be created. Can\'t carry on a process.';
2221. $this->translation['destination_dir_missing'] = 'Destination directory doesn\'t exist. Can\'t carry on a process.';
2222. $this->translation['destination_path_not_dir'] = 'Destination path is not a directory. Can\'t carry on a process.';
2223. $this->translation['destination_dir_write'] = 'Destination directory can\'t be made writeable. Can\'t carry on a process.';
2224. $this->translation['destination_path_write'] = 'Destination path is not a writeable. Can\'t carry on a process.';
2225. $this->translation['temp_file'] = 'Can\'t create the temporary file. Can\'t carry on a process.';
2226. $this->translation['source_not_readable'] = 'Source file is not readable. Can\'t carry on a process.';
2227. $this->translation['no_create_support'] = 'No create from %s support.';
2228. $this->translation['create_error'] = 'Error in creating %s image from source.';
2229. $this->translation['source_invalid'] = 'Can\'t read image source. Not an image?.';
2230. $this->translation['gd_missing'] = 'GD doesn\'t seem to be present.';
2231. $this->translation['watermark_no_create_support'] = 'No create from %s support, can\'t read watermark.';
2232. $this->translation['watermark_create_error'] = 'No %s read support, can\'t create watermark.';
2233. $this->translation['watermark_invalid'] = 'Unknown image format, can\'t read watermark.';
2234. $this->translation['file_create'] = 'No %s create support.';
2235. $this->translation['no_conversion_type'] = 'No conversion type defined.';
2236. $this->translation['copy_failed'] = 'Error copying file on the server. copy() failed.';
2237. $this->translation['reading_failed'] = 'Error reading the file.';
2239. // determines the language
2240. $this->lang = $lang;
2241. if ($this->lang != 'en_GB' && file_exists(dirname(__FILE__).'/lang') && file_exists(dirname(__FILE__).'/lang/class.upload.' . $lang . '.php')) {
2242. $translation = null;
2243. include(dirname(__FILE__).'/lang/class.upload.' . $lang . '.php');
2244. if (is_array($translation)) {
2245. $this->translation = array_merge($this->translation, $translation);
2246. } else {
2247. $this->lang = 'en_GB';
2248. }
2249. }
2252. // determines the supported MIME types, and matching image format
2253. $this->image_supported = array();
2254. if ($this->gdversion()) {
2255. if (imagetypes() & IMG_GIF) {
2256. $this->image_supported['image/gif'] = 'gif';
2257. }
2258. if (imagetypes() & IMG_JPG) {
2259. $this->image_supported['image/jpg'] = 'jpg';
2260. $this->image_supported['image/jpeg'] = 'jpg';
2261. $this->image_supported['image/pjpeg'] = 'jpg';
2262. }
2263. if (imagetypes() & IMG_PNG) {
2264. $this->image_supported['image/png'] = 'png';
2265. $this->image_supported['image/x-png'] = 'png';
2266. }
2267. if (imagetypes() & IMG_WBMP) {
2268. $this->image_supported['image/bmp'] = 'bmp';
2269. $this->image_supported['image/x-ms-bmp'] = 'bmp';
2270. $this->image_supported['image/x-windows-bmp'] = 'bmp';
2271. }
2272. }
2274. // display some system information
2275. if (empty($this->log)) {
2276. $this->log .= '<b>system information</b><br />';
2277. $inis = ini_get_all();
2278. $open_basedir = (array_key_exists('open_basedir', $inis) && array_key_exists('local_value', $inis['open_basedir']) && !empty($inis['open_basedir']['local_value'])) ? $inis['open_basedir']['local_value'] : false;
2279. $gd = $this->gdversion() ? $this->gdversion(true) : 'GD not present';
2280. $supported = trim((in_array('png', $this->image_supported) ? 'png' : '') . ' ' . (in_array('jpg', $this->image_supported) ? 'jpg' : '') . ' ' . (in_array('gif', $this->image_supported) ? 'gif' : '') . ' ' . (in_array('bmp', $this->image_supported) ? 'bmp' : ''));
2281. $this->log .= '-&nbsp;class version : ' . $this->version . '<br />';
2282. $this->log .= '-&nbsp;operating system : ' . PHP_OS . '<br />';
2283. $this->log .= '-&nbsp;PHP version : ' . PHP_VERSION . '<br />';
2284. $this->log .= '-&nbsp;GD version : ' . $gd . '<br />';
2285. $this->log .= '-&nbsp;supported image types : ' . (!empty($supported) ? $supported : 'none') . '<br />';
2286. $this->log .= '-&nbsp;open_basedir : ' . (!empty($open_basedir) ? $open_basedir : 'no restriction') . '<br />';
2287. $this->log .= '-&nbsp;language : ' . $this->lang . '<br />';
2288. }
2290. if (!$file) {
2291. $this->uploaded = false;
2292. $this->error = $this->translate('file_error');
2293. }
2295. // check if we sent a local filename rather than a $_FILE element
2296. if (!is_array($file)) {
2297. if (empty($file)) {
2298. $this->uploaded = false;
2299. $this->error = $this->translate('file_error');
2300. } else {
2301. $this->no_upload_check = TRUE;
2302. // this is a local filename, i.e.not uploaded
2303. $this->log .= '<b>' . $this->translate("source is a local file") . ' ' . $file . '</b><br />';
2305. if ($this->uploaded && !file_exists($file)) {
2306. $this->uploaded = false;
2307. $this->error = $this->translate('local_file_missing');
2308. }
2310. if ($this->uploaded && !is_readable($file)) {
2311. $this->uploaded = false;
2312. $this->error = $this->translate('local_file_not_readable');
2313. }
2315. if ($this->uploaded) {
2316. $this->file_src_pathname = $file;
2317. $this->file_src_name = basename($file);
2318. $this->log .= '- local file name OK<br />';
2319. preg_match('/\.([^\.]*$)/', $this->file_src_name, $extension);
2320. if (is_array($extension) && sizeof($extension) > 0) {
2321. $this->file_src_name_ext = strtolower($extension[1]);
2322. $this->file_src_name_body = substr($this->file_src_name, 0, ((strlen($this->file_src_name) - strlen($this->file_src_name_ext)))-1);
2323. } else {
2324. $this->file_src_name_ext = '';
2325. $this->file_src_name_body = $this->file_src_name;
2326. }
2327. $this->file_src_size = (file_exists($file) ? filesize($file) : 0);
2328. }
2329. $this->file_src_error = 0;
2330. }
2331. } else {
2332. // this is an element from $_FILE, i.e. an uploaded file
2333. $this->log .= '<b>source is an uploaded file</b><br />';
2334. if ($this->uploaded) {
2335. $this->file_src_error = trim($file['error']);
2336. switch($this->file_src_error) {
2337. case UPLOAD_ERR_OK:
2338. // all is OK
2339. $this->log .= '- upload OK<br />';
2340. break;
2341. case UPLOAD_ERR_INI_SIZE:
2342. $this->uploaded = false;
2343. $this->error = $this->translate('uploaded_too_big_ini');
2344. break;
2345. case UPLOAD_ERR_FORM_SIZE:
2346. $this->uploaded = false;
2347. $this->error = $this->translate('uploaded_too_big_html');
2348. break;
2349. case UPLOAD_ERR_PARTIAL:
2350. $this->uploaded = false;
2351. $this->error = $this->translate('uploaded_partial');
2352. break;
2353. case UPLOAD_ERR_NO_FILE:
2354. $this->uploaded = false;
2355. $this->error = $this->translate('uploaded_missing');
2356. break;
2357. case @UPLOAD_ERR_NO_TMP_DIR:
2358. $this->uploaded = false;
2359. $this->error = $this->translate('uploaded_no_tmp_dir');
2360. break;
2361. case @UPLOAD_ERR_CANT_WRITE:
2362. $this->uploaded = false;
2363. $this->error = $this->translate('uploaded_cant_write');
2364. break;
2365. case @UPLOAD_ERR_EXTENSION:
2366. $this->uploaded = false;
2367. $this->error = $this->translate('uploaded_err_extension');
2368. break;
2369. default:
2370. $this->uploaded = false;
2371. $this->error = $this->translate('uploaded_unknown') . ' ('.$this->file_src_error.')';
2372. }
2373. }
2375. if ($this->uploaded) {
2376. $this->file_src_pathname = $file['tmp_name'];
2377. $this->file_src_name = $file['name'];
2378. if ($this->file_src_name == '') {
2379. $this->uploaded = false;
2380. $this->error = $this->translate('try_again');
2381. }
2382. }
2384. if ($this->uploaded) {
2385. $this->log .= '- file name OK<br />';
2386. preg_match('/\.([^\.]*$)/', $this->file_src_name, $extension);
2387. if (is_array($extension) && sizeof($extension) > 0) {
2388. $this->file_src_name_ext = strtolower($extension[1]);
2389. $this->file_src_name_body = substr($this->file_src_name, 0, ((strlen($this->file_src_name) - strlen($this->file_src_name_ext)))-1);
2390. } else {
2391. $this->file_src_name_ext = '';
2392. $this->file_src_name_body = $this->file_src_name;
2393. }
2394. $this->file_src_size = $file['size'];
2395. $mime_from_browser = $file['type'];
2396. }
2397. }
2399. if ($this->uploaded) {
2400. $this->log .= '<b>determining MIME type</b><br />';
2401. $this->file_src_mime = null;
2403. // checks MIME type with Fileinfo PECL extension
2404. if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) {
2405. if ($this->mime_fileinfo) {
2406. $this->log .= '- Checking MIME type with Fileinfo PECL extension<br />';
2407. if (function_exists('finfo_open')) {
2408. if ($this->mime_fileinfo !== '') {
2409. if ($this->mime_fileinfo === true) {
2410. if (getenv('MAGIC') === FALSE) {
2411. if (substr(PHP_OS, 0, 3) == 'WIN') {
2412. $path = realpath(ini_get('extension_dir') . '/../') . 'extras/magic';
2413. } else {
2414. $path = '/usr/share/file/magic';
2415. }
2416. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MAGIC path defaults to ' . $path . '<br />';
2417. } else {
2418. $path = getenv('MAGIC');
2419. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MAGIC path is set to ' . $path . ' from MAGIC variable<br />';
2420. }
2421. } else {
2422. $path = $this->mime_fileinfo;
2423. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MAGIC path is set to ' . $path . '<br />';
2424. }
2425. $f = @finfo_open(FILEINFO_MIME, $path);
2426. } else {
2427. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MAGIC path will not be used<br />';
2428. $f = @finfo_open(FILEINFO_MIME);
2429. }
2430. if (is_resource($f)) {
2431. $mime = finfo_file($f, realpath($this->file_src_pathname));
2432. finfo_close($f);
2433. $this->file_src_mime = $mime;
2434. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MIME type detected as ' . $this->file_src_mime . ' by Fileinfo PECL extension<br />';
2435. if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) {
2436. $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime);
2437. $this->log .= '-&nbsp;MIME validated as ' . $this->file_src_mime . '<br />';
2438. } else {
2439. $this->file_src_mime = null;
2440. }
2441. } else {
2442. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;Fileinfo PECL extension failed (finfo_open)<br />';
2443. }
2444. } elseif (class_exists('finfo')) {
2445. $f = new finfo( FILEINFO_MIME );
2446. if ($f) {
2447. $this->file_src_mime = $f->file(realpath($this->file_src_pathname));
2448. $this->log .= '- MIME type detected as ' . $this->file_src_mime . ' by Fileinfo PECL extension<br />';
2449. if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) {
2450. $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime);
2451. $this->log .= '-&nbsp;MIME validated as ' . $this->file_src_mime . '<br />';
2452. } else {
2453. $this->file_src_mime = null;
2454. }
2455. } else {
2456. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;Fileinfo PECL extension failed (finfo)<br />';
2457. }
2458. } else {
2459. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;Fileinfo PECL extension not available<br />';
2460. }
2461. } else {
2462. $this->log .= '- Fileinfo PECL extension deactivated<br />';
2463. }
2464. }
2466. // checks MIME type with shell if unix access is authorized
2467. if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) {
2468. if ($this->mime_file) {
2469. $this->log .= '- Checking MIME type with UNIX file() command<br />';
2470. if (substr(PHP_OS, 0, 3) != 'WIN') {
2471. if (strlen($mime = @exec("file -bi ".escapeshellarg($this->file_src_pathname))) != 0) {
2472. $this->file_src_mime = trim($mime);
2473. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MIME type detected as ' . $this->file_src_mime . ' by UNIX file() command<br />';
2474. if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) {
2475. $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime);
2476. $this->log .= '-&nbsp;MIME validated as ' . $this->file_src_mime . '<br />';
2477. } else {
2478. $this->file_src_mime = null;
2479. }
2480. } else {
2481. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;UNIX file() command failed<br />';
2482. }
2483. } else {
2484. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;UNIX file() command not availabled<br />';
2485. }
2486. } else {
2487. $this->log .= '- UNIX file() command is deactivated<br />';
2488. }
2489. }
2491. // checks MIME type with mime_magic
2492. if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) {
2493. if ($this->mime_magic) {
2494. $this->log .= '- Checking MIME type with mime.magic file (mime_content_type())<br />';
2495. if (function_exists('mime_content_type')) {
2496. $this->file_src_mime = mime_content_type($this->file_src_pathname);
2497. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MIME type detected as ' . $this->file_src_mime . ' by mime_content_type()<br />';
2498. if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) {
2499. $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime);
2500. $this->log .= '-&nbsp;MIME validated as ' . $this->file_src_mime . '<br />';
2501. } else {
2502. $this->file_src_mime = null;
2503. }
2504. } else {
2505. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;mime_content_type() is not available<br />';
2506. }
2507. } else {
2508. $this->log .= '- mime.magic file (mime_content_type()) is deactivated<br />';
2509. }
2510. }
2512. // checks MIME type with getimagesize()
2513. if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) {
2514. if ($this->mime_getimagesize) {
2515. $this->log .= '- Checking MIME type with getimagesize()<br />';
2516. $info = getimagesize($this->file_src_pathname);
2517. if (is_array($info) && array_key_exists('mime', $info)) {
2518. $this->file_src_mime = trim($info['mime']);
2519. if (empty($this->file_src_mime)) {
2520. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MIME empty, guessing from type<br />';
2521. $mime = (is_array($info) && array_key_exists(2, $info) ? $info[2] : null); // 1 = GIF, 2 = JPG, 3 = PNG
2522. $this->file_src_mime = ($mime==IMAGETYPE_GIF ? 'image/gif' : ($mime==IMAGETYPE_JPEG ? 'image/jpeg' : ($mime==IMAGETYPE_PNG ? 'image/png' : ($mime==IMAGETYPE_BMP ? 'image/bmp' : null))));
2523. }
2524. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;MIME type detected as ' . $this->file_src_mime . ' by PHP getimagesize() function<br />';
2525. if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) {
2526. $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime);
2527. $this->log .= '-&nbsp;MIME validated as ' . $this->file_src_mime . '<br />';
2528. } else {
2529. $this->file_src_mime = null;
2530. }
2531. } else {
2532. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;getimagesize() failed<br />';
2533. }
2534. } else {
2535. $this->log .= '- getimagesize() is deactivated<br />';
2536. }
2537. }
2539. // default to MIME from browser (or Flash)
2540. if (!empty($mime_from_browser) && !$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime)) {
2541. $this->file_src_mime =$mime_from_browser;
2542. $this->log .= '- MIME type detected as ' . $this->file_src_mime . ' by browser<br />';
2543. if (preg_match("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", $this->file_src_mime)) {
2544. $this->file_src_mime = preg_replace("/^([\.-\w]+)\/([\.-\w]+)(.*)$/i", '$1/$2', $this->file_src_mime);
2545. $this->log .= '-&nbsp;MIME validated as ' . $this->file_src_mime . '<br />';
2546. } else {
2547. $this->file_src_mime = null;
2548. }
2549. }
2551. // we need to work some magic if we upload via Flash
2552. if ($this->file_src_mime == 'application/octet-stream' || !$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) {
2553. if ($this->file_src_mime == 'application/octet-stream') $this->log .= '- Flash may be rewriting MIME as application/octet-stream<br />';
2554. $this->log .= '- Try to guess MIME type from file extension (' . $this->file_src_name_ext . '): ';
2555. switch($this->file_src_name_ext) {
2556. case 'jpg':
2557. case 'jpeg':
2558. case 'jpe':
2559. $this->file_src_mime = 'image/jpeg';
2560. break;
2561. case 'gif':
2562. $this->file_src_mime = 'image/gif';
2563. break;
2564. case 'png':
2565. $this->file_src_mime = 'image/png';
2566. break;
2567. case 'bmp':
2568. $this->file_src_mime = 'image/bmp';
2569. break;
2570. case 'flv':
2571. $this->file_src_mime = 'video/x-flv';
2572. break;
2573. case 'js' :
2574. $this->file_src_mime = 'application/x-javascript';
2575. break;
2576. case 'json' :
2577. $this->file_src_mime = 'application/json';
2578. break;
2579. case 'tiff' :
2580. $this->file_src_mime = 'image/tiff';
2581. break;
2582. case 'css' :
2583. $this->file_src_mime = 'text/css';
2584. break;
2585. case 'xml' :
2586. $this->file_src_mime = 'application/xml';
2587. break;
2588. case 'doc' :
2589. case 'docx' :
2590. $this->file_src_mime = 'application/msword';
2591. break;
2592. case 'xls' :
2593. case 'xlt' :
2594. case 'xlm' :
2595. case 'xld' :
2596. case 'xla' :
2597. case 'xlc' :
2598. case 'xlw' :
2599. case 'xll' :
2600. $this->file_src_mime = 'application/vnd.ms-excel';
2601. break;
2602. case 'ppt' :
2603. case 'pps' :
2604. $this->file_src_mime = 'application/vnd.ms-powerpoint';
2605. break;
2606. case 'rtf' :
2607. $this->file_src_mime = 'application/rtf';
2608. break;
2609. case 'pdf' :
2610. $this->file_src_mime = 'application/pdf';
2611. break;
2612. case 'html' :
2613. case 'htm' :
2614. case 'php' :
2615. $this->file_src_mime = 'text/html';
2616. break;
2617. case 'txt' :
2618. $this->file_src_mime = 'text/plain';
2619. break;
2620. case 'mpeg' :
2621. case 'mpg' :
2622. case 'mpe' :
2623. $this->file_src_mime = 'video/mpeg';
2624. break;
2625. case 'mp3' :
2626. $this->file_src_mime = 'audio/mpeg3';
2627. break;
2628. case 'wav' :
2629. $this->file_src_mime = 'audio/wav';
2630. break;
2631. case 'aiff' :
2632. case 'aif' :
2633. $this->file_src_mime = 'audio/aiff';
2634. break;
2635. case 'avi' :
2636. $this->file_src_mime = 'video/msvideo';
2637. break;
2638. case 'wmv' :
2639. $this->file_src_mime = 'video/x-ms-wmv';
2640. break;
2641. case 'mov' :
2642. $this->file_src_mime = 'video/quicktime';
2643. break;
2644. case 'zip' :
2645. $this->file_src_mime = 'application/zip';
2646. break;
2647. case 'tar' :
2648. $this->file_src_mime = 'application/x-tar';
2649. break;
2650. case 'swf' :
2651. $this->file_src_mime = 'application/x-shockwave-flash';
2652. break;
2653. case 'odt':
2654. $this->file_src_mime = 'application/vnd.oasis.opendocument.text';
2655. break;
2656. case 'ott':
2657. $this->file_src_mime = 'application/vnd.oasis.opendocument.text-template';
2658. break;
2659. case 'oth':
2660. $this->file_src_mime = 'application/vnd.oasis.opendocument.text-web';
2661. break;
2662. case 'odm':
2663. $this->file_src_mime = 'application/vnd.oasis.opendocument.text-master';
2664. break;
2665. case 'odg':
2666. $this->file_src_mime = 'application/vnd.oasis.opendocument.graphics';
2667. break;
2668. case 'otg':
2669. $this->file_src_mime = 'application/vnd.oasis.opendocument.graphics-template';
2670. break;
2671. case 'odp':
2672. $this->file_src_mime = 'application/vnd.oasis.opendocument.presentation';
2673. break;
2674. case 'otp':
2675. $this->file_src_mime = 'application/vnd.oasis.opendocument.presentation-template';
2676. break;
2677. case 'ods':
2678. $this->file_src_mime = 'application/vnd.oasis.opendocument.spreadsheet';
2679. break;
2680. case 'ots':
2681. $this->file_src_mime = 'application/vnd.oasis.opendocument.spreadsheet-template';
2682. break;
2683. case 'odc':
2684. $this->file_src_mime = 'application/vnd.oasis.opendocument.chart';
2685. break;
2686. case 'odf':
2687. $this->file_src_mime = 'application/vnd.oasis.opendocument.formula';
2688. break;
2689. case 'odb':
2690. $this->file_src_mime = 'application/vnd.oasis.opendocument.database';
2691. break;
2692. case 'odi':
2693. $this->file_src_mime = 'application/vnd.oasis.opendocument.image';
2694. break;
2695. case 'oxt':
2696. $this->file_src_mime = 'application/vnd.openofficeorg.extension';
2697. break;
2698. case 'docx':
2699. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
2700. break;
2701. case 'docm':
2702. $this->file_src_mime = 'application/vnd.ms-word.document.macroEnabled.12';
2703. break;
2704. case 'dotx':
2705. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.template';
2706. break;
2707. case 'dotm':
2708. $this->file_src_mime = 'application/vnd.ms-word.template.macroEnabled.12';
2709. break;
2710. case 'xlsx':
2711. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
2712. break;
2713. case 'xlsm':
2714. $this->file_src_mime = 'application/vnd.ms-excel.sheet.macroEnabled.12';
2715. break;
2716. case 'xltx':
2717. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.template';
2718. break;
2719. case 'xltm':
2720. $this->file_src_mime = 'application/vnd.ms-excel.template.macroEnabled.12';
2721. break;
2722. case 'xlsb':
2723. $this->file_src_mime = 'application/vnd.ms-excel.sheet.binary.macroEnabled.12';
2724. break;
2725. case 'xlam':
2726. $this->file_src_mime = 'application/vnd.ms-excel.addin.macroEnabled.12';
2727. break;
2728. case 'pptx':
2729. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
2730. break;
2731. case 'pptm':
2732. $this->file_src_mime = 'application/vnd.ms-powerpoint.presentation.macroEnabled.12';
2733. break;
2734. case 'ppsx':
2735. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow';
2736. break;
2737. case 'ppsm':
2738. $this->file_src_mime = 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12';
2739. break;
2740. case 'potx':
2741. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.presentationml.template';
2742. break;
2743. case 'potm':
2744. $this->file_src_mime = 'application/vnd.ms-powerpoint.template.macroEnabled.12';
2745. break;
2746. case 'ppam':
2747. $this->file_src_mime = 'application/vnd.ms-powerpoint.addin.macroEnabled.12';
2748. break;
2749. case 'sldx':
2750. $this->file_src_mime = 'application/vnd.openxmlformats-officedocument.presentationml.slide';
2751. break;
2752. case 'sldm':
2753. $this->file_src_mime = 'application/vnd.ms-powerpoint.slide.macroEnabled.12';
2754. break;
2755. case 'thmx':
2756. $this->file_src_mime = 'application/vnd.ms-officetheme';
2757. break;
2758. case 'onetoc':
2759. case 'onetoc2':
2760. case 'onetmp':
2761. case 'onepkg':
2762. $this->file_src_mime = 'application/onenote';
2763. break;
2764. }
2765. if ($this->file_src_mime == 'application/octet-stream') {
2766. $this->log .= 'doesn\'t look like anything known<br />';
2767. } else {
2768. $this->log .= 'MIME type set to ' . $this->file_src_mime . '<br />';
2769. }
2770. }
2772. if (!$this->file_src_mime || !is_string($this->file_src_mime) || empty($this->file_src_mime) || strpos($this->file_src_mime, '/') === FALSE) {
2773. $this->log .= '- MIME type couldn\'t be detected! (' . (string) $this->file_src_mime . ')<br />';
2774. }
2776. // determine whether the file is an image
2777. if ($this->file_src_mime && is_string($this->file_src_mime) && !empty($this->file_src_mime) && array_key_exists($this->file_src_mime, $this->image_supported)) {
2778. $this->file_is_image = true;
2779. $this->image_src_type = $this->image_supported[$this->file_src_mime];
2780. }
2782. // if the file is an image, we gather some useful data
2783. if ($this->file_is_image) {
2784. if ($h = fopen($this->file_src_pathname, 'r')) {
2785. fclose($h);
2786. $info = getimagesize($this->file_src_pathname);
2787. if (is_array($info)) {
2788. $this->image_src_x = $info[0];
2789. $this->image_src_y = $info[1];
2790. $this->image_dst_x = $this->image_src_x;
2791. $this->image_dst_y = $this->image_src_y;
2792. $this->image_src_pixels = $this->image_src_x * $this->image_src_y;
2793. $this->image_src_bits = array_key_exists('bits', $info) ? $info['bits'] : null;
2794. } else {
2795. $this->file_is_image = false;
2796. $this->uploaded = false;
2797. $this->log .= '- can\'t retrieve image information, image may have been tampered with<br />';
2798. $this->error = $this->translate('incorrect_file');
2799. }
2800. } else {
2801. $this->log .= '- can\'t read source file directly. open_basedir restriction in place?<br />';
2802. }
2803. }
2805. $this->log .= '<b>source variables</b><br />';
2806. $this->log .= '- You can use all these before calling process()<br />';
2807. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_src_name : ' . $this->file_src_name . '<br />';
2808. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_src_name_body : ' . $this->file_src_name_body . '<br />';
2809. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_src_name_ext : ' . $this->file_src_name_ext . '<br />';
2810. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_src_pathname : ' . $this->file_src_pathname . '<br />';
2811. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_src_mime : ' . $this->file_src_mime . '<br />';
2812. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_src_size : ' . $this->file_src_size . ' (max= ' . $this->file_max_size . ')<br />';
2813. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_src_error : ' . $this->file_src_error . '<br />';
2815. if ($this->file_is_image) {
2816. $this->log .= '- source file is an image<br />';
2817. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image_src_x : ' . $this->image_src_x . '<br />';
2818. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image_src_y : ' . $this->image_src_y . '<br />';
2819. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image_src_pixels : ' . $this->image_src_pixels . '<br />';
2820. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image_src_type : ' . $this->image_src_type . '<br />';
2821. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image_src_bits : ' . $this->image_src_bits . '<br />';
2822. }
2823. }
2825. }
2827. /**
2828. * Returns the version of GD
2829. *
2830. * @access public
2831. * @param boolean $full Optional flag to get precise version
2832. * @return float GD version
2833. */
2834. function gdversion($full = false) {
2835. static $gd_version = null;
2836. static $gd_full_version = null;
2837. if ($gd_version === null) {
2838. if (function_exists('gd_info')) {
2839. $gd = gd_info();
2840. $gd = $gd["GD Version"];
2841. $regex = "/([\d\.]+)/i";
2842. } else {
2843. ob_start();
2844. phpinfo(8);
2845. $gd = ob_get_contents();
2846. ob_end_clean();
2847. $regex = "/\bgd\s+version\b[^\d\n\r]+?([\d\.]+)/i";
2848. }
2849. if (preg_match($regex, $gd, $m)) {
2850. $gd_full_version = (string) $m[1];
2851. $gd_version = (float) $m[1];
2852. } else {
2853. $gd_full_version = 'none';
2854. $gd_version = 0;
2855. }
2856. }
2857. if ($full) {
2858. return $gd_full_version;
2859. } else {
2860. return $gd_version;
2861. }
2862. }
2865. /**
2866. * Creates directories recursively
2867. *
2868. * @access private
2869. * @param string $path Path to create
2870. * @param integer $mode Optional permissions
2871. * @return boolean Success
2872. */
2873. function rmkdir($path, $mode = 0777) {
2874. return is_dir($path) || ( $this->rmkdir(dirname($path), $mode) && $this->_mkdir($path, $mode) );
2875. }
2878. /**
2879. * Creates directory
2880. *
2881. * @access private
2882. * @param string $path Path to create
2883. * @param integer $mode Optional permissions
2884. * @return boolean Success
2885. */
2886. function _mkdir($path, $mode = 0777) {
2887. $old = umask(0);
2888. $res = @mkdir($path, $mode);
2889. umask($old);
2890. return $res;
2891. }
2894. /**
2895. * Translate error messages
2896. *
2897. * @access private
2898. * @param string $str Message to translate
2899. * @param array $tokens Optional token values
2900. * @return string Translated string
2901. */
2902. function translate($str, $tokens = array()) {
2903. if (array_key_exists($str, $this->translation)) $str = $this->translation[$str];
2904. if (is_array($tokens) && sizeof($tokens) > 0) $str = vsprintf($str, $tokens);
2905. return $str;
2906. }
2908. /**
2909. * Decodes colors
2910. *
2911. * @access private
2912. * @param string $color Color string
2913. * @return array RGB colors
2914. */
2915. function getcolors($color) {
2916. $r = sscanf($color, "#%2x%2x%2x");
2917. $red = (array_key_exists(0, $r) && is_numeric($r[0]) ? $r[0] : 0);
2918. $green = (array_key_exists(1, $r) && is_numeric($r[1]) ? $r[1] : 0);
2919. $blue = (array_key_exists(2, $r) && is_numeric($r[2]) ? $r[2] : 0);
2920. return array($red, $green, $blue);
2921. }
2923. /**
2924. * Creates a container image
2925. *
2926. * @access private
2927. * @param integer $x Width
2928. * @param integer $y Height
2929. * @param boolean $fill Optional flag to draw the background color or not
2930. * @param boolean $trsp Optional flag to set the background to be transparent
2931. * @return resource Container image
2932. */
2933. function imagecreatenew($x, $y, $fill = true, $trsp = false) {
2934. if ($x < 1) $x = 1; if ($y < 1) $y = 1;
2935. if ($this->gdversion() >= 2 && !$this->image_is_palette) {
2936. // create a true color image
2937. $dst_im = imagecreatetruecolor($x, $y);
2938. // this preserves transparency in PNGs, in true color
2939. if (empty($this->image_background_color) || $trsp) {
2940. imagealphablending($dst_im, false );
2941. imagefilledrectangle($dst_im, 0, 0, $x, $y, imagecolorallocatealpha($dst_im, 0, 0, 0, 127));
2942. }
2943. } else {
2944. // creates a palette image
2945. $dst_im = imagecreate($x, $y);
2946. // preserves transparency for palette images, if the original image has transparency
2947. if (($fill && $this->image_is_transparent && empty($this->image_background_color)) || $trsp) {
2948. imagefilledrectangle($dst_im, 0, 0, $x, $y, $this->image_transparent_color);
2949. imagecolortransparent($dst_im, $this->image_transparent_color);
2950. }
2951. }
2952. // fills with background color if any is set
2953. if ($fill && !empty($this->image_background_color) && !$trsp) {
2954. list($red, $green, $blue) = $this->getcolors($this->image_background_color);
2955. $background_color = imagecolorallocate($dst_im, $red, $green, $blue);
2956. imagefilledrectangle($dst_im, 0, 0, $x, $y, $background_color);
2957. }
2958. return $dst_im;
2959. }
2962. /**
2963. * Transfers an image from the container to the destination image
2964. *
2965. * @access private
2966. * @param resource $src_im Container image
2967. * @param resource $dst_im Destination image
2968. * @return resource Destination image
2969. */
2970. function imagetransfer($src_im, $dst_im) {
2971. if (is_resource($dst_im)) imagedestroy($dst_im);
2972. $dst_im = & $src_im;
2973. return $dst_im;
2974. }
2976. /**
2977. * Merges two images
2978. *
2979. * If the output format is PNG, then we do it pixel per pixel to retain the alpha channel
2980. *
2981. * @access private
2982. * @param resource $dst_img Destination image
2983. * @param resource $src_img Overlay image
2984. * @param int $dst_x x-coordinate of destination point
2985. * @param int $dst_y y-coordinate of destination point
2986. * @param int $src_x x-coordinate of source point
2987. * @param int $src_y y-coordinate of source point
2988. * @param int $src_w Source width
2989. * @param int $src_h Source height
2990. * @param int $pct Optional percentage of the overlay, between 0 and 100 (default: 100)
2991. * @return resource Destination image
2992. */
2993. function imagecopymergealpha(&$dst_im, &$src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct = 0) {
2994. $dst_x = (int) $dst_x;
2995. $dst_y = (int) $dst_y;
2996. $src_x = (int) $src_x;
2997. $src_y = (int) $src_y;
2998. $src_w = (int) $src_w;
2999. $src_h = (int) $src_h;
3000. $pct = (int) $pct;
3001. $dst_w = imagesx($dst_im);
3002. $dst_h = imagesy($dst_im);
3004. for ($y = $src_y; $y < $src_h; $y++) {
3005. for ($x = $src_x; $x < $src_w; $x++) {
3007. if ($x + $dst_x >= 0 && $x + $dst_x < $dst_w && $x + $src_x >= 0 && $x + $src_x < $src_w
3008. && $y + $dst_y >= 0 && $y + $dst_y < $dst_h && $y + $src_y >= 0 && $y + $src_y < $src_h) {
3010. $dst_pixel = imagecolorsforindex($dst_im, imagecolorat($dst_im, $x + $dst_x, $y + $dst_y));
3011. $src_pixel = imagecolorsforindex($src_im, imagecolorat($src_im, $x + $src_x, $y + $src_y));
3013. $src_alpha = 1 - ($src_pixel['alpha'] / 127);
3014. $dst_alpha = 1 - ($dst_pixel['alpha'] / 127);
3015. $opacity = $src_alpha * $pct / 100;
3016. if ($dst_alpha >= $opacity) $alpha = $dst_alpha;
3017. if ($dst_alpha < $opacity) $alpha = $opacity;
3018. if ($alpha > 1) $alpha = 1;
3020. if ($opacity > 0) {
3021. $dst_red = round(( ($dst_pixel['red'] * $dst_alpha * (1 - $opacity)) ) );
3022. $dst_green = round(( ($dst_pixel['green'] * $dst_alpha * (1 - $opacity)) ) );
3023. $dst_blue = round(( ($dst_pixel['blue'] * $dst_alpha * (1 - $opacity)) ) );
3024. $src_red = round((($src_pixel['red'] * $opacity)) );
3025. $src_green = round((($src_pixel['green'] * $opacity)) );
3026. $src_blue = round((($src_pixel['blue'] * $opacity)) );
3027. $red = round(($dst_red + $src_red ) / ($dst_alpha * (1 - $opacity) + $opacity));
3028. $green = round(($dst_green + $src_green) / ($dst_alpha * (1 - $opacity) + $opacity));
3029. $blue = round(($dst_blue + $src_blue ) / ($dst_alpha * (1 - $opacity) + $opacity));
3030. if ($red > 255) $red = 255;
3031. if ($green > 255) $green = 255;
3032. if ($blue > 255) $blue = 255;
3033. $alpha = round((1 - $alpha) * 127);
3034. $color = imagecolorallocatealpha($dst_im, $red, $green, $blue, $alpha);
3035. imagesetpixel($dst_im, $x + $dst_x, $y + $dst_y, $color);
3036. }
3037. }
3038. }
3039. }
3040. return true;
3041. }
3045. /**
3046. * Actually uploads the file, and act on it according to the set processing class variables
3047. *
3048. * This function copies the uploaded file to the given location, eventually performing actions on it.
3049. * Typically, you can call {@link process} several times for the same file,
3050. * for instance to create a resized image and a thumbnail of the same file.
3051. * The original uploaded file remains intact in its temporary location, so you can use {@link process} several times.
3052. * You will be able to delete the uploaded file with {@link clean} when you have finished all your {@link process} calls.
3053. *
3054. * According to the processing class variables set in the calling file, the file can be renamed,
3055. * and if it is an image, can be resized or converted.
3056. *
3057. * When the processing is completed, and the file copied to its new location, the
3058. * processing class variables will be reset to their default value.
3059. * This allows you to set new properties, and perform another {@link process} on the same uploaded file
3060. *
3061. * If the function is called with a null or empty argument, then it will return the content of the picture
3062. *
3063. * It will set {@link processed} (and {@link error} is an error occurred)
3064. *
3065. * @access public
3066. * @param string $server_path Optional path location of the uploaded file, with an ending slash
3067. * @return string Optional content of the image
3068. */
3069. function process($server_path = null) {
3071. $this->error = '';
3072. $this->processed = true;
3073. $return_mode = false;
3074. $return_content = null;
3076. if (!$this->uploaded) {
3077. $this->error = $this->translate('file_not_uploaded');
3078. $this->processed = false;
3079. }
3081. if ($this->processed) {
3082. if (empty($server_path) || is_null($server_path)) {
3083. $this->log .= '<b>process file and return the content</b><br />';
3084. $return_mode = true;
3085. } else {
3086. if(strtolower(substr(PHP_OS, 0, 3)) === 'win') {
3087. if (substr($server_path, -1, 1) != '\\') $server_path = $server_path . '\\';
3088. } else {
3089. if (substr($server_path, -1, 1) != '/') $server_path = $server_path . '/';
3090. }
3091. $this->log .= '<b>process file to ' . $server_path . '</b><br />';
3092. }
3093. }
3095. if ($this->processed) {
3096. // checks file max size
3097. if ($this->file_src_size > $this->file_max_size ) {
3098. $this->processed = false;
3099. $this->error = $this->translate('file_too_big');
3100. } else {
3101. $this->log .= '- file size OK<br />';
3102. }
3103. }
3105. if ($this->processed) {
3106. // turn dangerous scripts into text files
3107. if ($this->no_script) {
3108. if (((substr($this->file_src_mime, 0, 5) == 'text/' || strpos($this->file_src_mime, 'javascript') !== false) && (substr($this->file_src_name, -4) != '.txt'))
3109. || preg_match('/\.(php|pl|py|cgi|asp)$/i', $this->file_src_name) || empty($this->file_src_name_ext)) {
3110. $this->file_src_mime = 'text/plain';
3111. $this->log .= '- script ' . $this->file_src_name . ' renamed as ' . $this->file_src_name . '.txt!<br />';
3112. $this->file_src_name_ext .= (empty($this->file_src_name_ext) ? 'txt' : '.txt');
3113. }
3114. }
3116. if ($this->mime_check && empty($this->file_src_mime)) {
3117. $this->processed = false;
3118. $this->error = $this->translate('no_mime');
3119. } else if ($this->mime_check && !empty($this->file_src_mime) && strpos($this->file_src_mime, '/') !== false) {
3120. list($m1, $m2) = explode('/', $this->file_src_mime);
3121. $allowed = false;
3122. // check wether the mime type is allowed
3123. foreach($this->allowed as $k => $v) {
3124. list($v1, $v2) = explode('/', $v);
3125. if (($v1 == '*' && $v2 == '*') || ($v1 == $m1 && ($v2 == $m2 || $v2 == '*'))) {
3126. $allowed = true;
3127. break;
3128. }
3129. }
3130. // check wether the mime type is forbidden
3131. foreach($this->forbidden as $k => $v) {
3132. list($v1, $v2) = explode('/', $v);
3133. if (($v1 == '*' && $v2 == '*') || ($v1 == $m1 && ($v2 == $m2 || $v2 == '*'))) {
3134. $allowed = false;
3135. break;
3136. }
3137. }
3138. if (!$allowed) {
3139. $this->processed = false;
3140. $this->error = $this->translate('incorrect_file');
3141. } else {
3142. $this->log .= '- file mime OK : ' . $this->file_src_mime . '<br />';
3143. }
3144. } else {
3145. $this->log .= '- file mime (not checked) : ' . $this->file_src_mime . '<br />';
3146. }
3148. // if the file is an image, we can check on its dimensions
3149. // these checks are not available if open_basedir restrictions are in place
3150. if ($this->file_is_image) {
3151. if (is_numeric($this->image_src_x) && is_numeric($this->image_src_y)) {
3152. $ratio = $this->image_src_x / $this->image_src_y;
3153. if (!is_null($this->image_max_width) && $this->image_src_x > $this->image_max_width) {
3154. $this->processed = false;
3155. $this->error = $this->translate('image_too_wide');
3156. }
3157. if (!is_null($this->image_min_width) && $this->image_src_x < $this->image_min_width) {
3158. $this->processed = false;
3159. $this->error = $this->translate('image_too_narrow');
3160. }
3161. if (!is_null($this->image_max_height) && $this->image_src_y > $this->image_max_height) {
3162. $this->processed = false;
3163. $this->error = $this->translate('image_too_high');
3164. }
3165. if (!is_null($this->image_min_height) && $this->image_src_y < $this->image_min_height) {
3166. $this->processed = false;
3167. $this->error = $this->translate('image_too_short');
3168. }
3169. if (!is_null($this->image_max_ratio) && $ratio > $this->image_max_ratio) {
3170. $this->processed = false;
3171. $this->error = $this->translate('ratio_too_high');
3172. }
3173. if (!is_null($this->image_min_ratio) && $ratio < $this->image_min_ratio) {
3174. $this->processed = false;
3175. $this->error = $this->translate('ratio_too_low');
3176. }
3177. if (!is_null($this->image_max_pixels) && $this->image_src_pixels > $this->image_max_pixels) {
3178. $this->processed = false;
3179. $this->error = $this->translate('too_many_pixels');
3180. }
3181. if (!is_null($this->image_min_pixels) && $this->image_src_pixels < $this->image_min_pixels) {
3182. $this->processed = false;
3183. $this->error = $this->translate('not_enough_pixels');
3184. }
3185. } else {
3186. $this->log .= '- no image properties available, can\'t enforce dimension checks : ' . $this->file_src_mime . '<br />';
3187. }
3188. }
3189. }
3191. if ($this->processed) {
3192. $this->file_dst_path = $server_path;
3194. // repopulate dst variables from src
3195. $this->file_dst_name = $this->file_src_name;
3196. $this->file_dst_name_body = $this->file_src_name_body;
3197. $this->file_dst_name_ext = $this->file_src_name_ext;
3198. if ($this->file_overwrite) $this->file_auto_rename = false;
3200. if ($this->image_convert != '') { // if we convert as an image
3201. $this->file_dst_name_ext = $this->image_convert;
3202. $this->log .= '- new file name ext : ' . $this->image_convert . '<br />';
3203. }
3204. if ($this->file_new_name_body != '') { // rename file body
3205. $this->file_dst_name_body = $this->file_new_name_body;
3206. $this->log .= '- new file name body : ' . $this->file_new_name_body . '<br />';
3207. }
3208. if ($this->file_new_name_ext != '') { // rename file ext
3209. $this->file_dst_name_ext = $this->file_new_name_ext;
3210. $this->log .= '- new file name ext : ' . $this->file_new_name_ext . '<br />';
3211. }
3212. if ($this->file_name_body_add != '') { // append a string to the name
3213. $this->file_dst_name_body = $this->file_dst_name_body . $this->file_name_body_add;
3214. $this->log .= '- file name body append : ' . $this->file_name_body_add . '<br />';
3215. }
3216. if ($this->file_name_body_pre != '') { // prepend a string to the name
3217. $this->file_dst_name_body = $this->file_name_body_pre . $this->file_dst_name_body;
3218. $this->log .= '- file name body prepend : ' . $this->file_name_body_pre . '<br />';
3219. }
3220. if ($this->file_safe_name) { // formats the name
3221. $this->file_dst_name_body = str_replace(array(' ', '-'), array('_','_'), $this->file_dst_name_body) ;
3222. $this->file_dst_name_body = preg_replace('/[^A-Za-z0-9_]/', '', $this->file_dst_name_body) ;
3223. $this->log .= '- file name safe format<br />';
3224. }
3226. $this->log .= '- destination variables<br />';
3227. if (empty($this->file_dst_path) || is_null($this->file_dst_path)) {
3228. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_dst_path : n/a<br />';
3229. } else {
3230. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_dst_path : ' . $this->file_dst_path . '<br />';
3231. }
3232. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_dst_name_body : ' . $this->file_dst_name_body . '<br />';
3233. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_dst_name_ext : ' . $this->file_dst_name_ext . '<br />';
3235. // do we do some image manipulation?
3236. $image_manipulation = ($this->file_is_image && (
3237. $this->image_resize
3238. || $this->image_convert != ''
3239. || is_numeric($this->image_brightness)
3240. || is_numeric($this->image_contrast)
3241. || is_numeric($this->image_threshold)
3242. || !empty($this->image_tint_color)
3243. || !empty($this->image_overlay_color)
3244. || !empty($this->image_text)
3245. || $this->image_greyscale
3246. || $this->image_negative
3247. || !empty($this->image_watermark)
3248. || is_numeric($this->image_rotate)
3249. || is_numeric($this->jpeg_size)
3250. || !empty($this->image_flip)
3251. || !empty($this->image_crop)
3252. || !empty($this->image_precrop)
3253. || !empty($this->image_border)
3254. || $this->image_frame > 0
3255. || $this->image_bevel > 0
3256. || $this->image_reflection_height));
3258. if ($image_manipulation) {
3259. if ($this->image_convert=='') {
3260. $this->file_dst_name = $this->file_dst_name_body . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : '');
3261. $this->log .= '- image operation, keep extension<br />';
3262. } else {
3263. $this->file_dst_name = $this->file_dst_name_body . '.' . $this->image_convert;
3264. $this->log .= '- image operation, change extension for conversion type<br />';
3265. }
3266. } else {
3267. $this->file_dst_name = $this->file_dst_name_body . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : '');
3268. $this->log .= '- no image operation, keep extension<br />';
3269. }
3271. if (!$return_mode) {
3272. if (!$this->file_auto_rename) {
3273. $this->log .= '- no auto_rename if same filename exists<br />';
3274. $this->file_dst_pathname = $this->file_dst_path . $this->file_dst_name;
3275. } else {
3276. $this->log .= '- checking for auto_rename<br />';
3277. $this->file_dst_pathname = $this->file_dst_path . $this->file_dst_name;
3278. $body = $this->file_dst_name_body;
3279. $cpt = 1;
3280. while (@file_exists($this->file_dst_pathname)) {
3281. $this->file_dst_name_body = $body . '_' . $cpt;
3282. $this->file_dst_name = $this->file_dst_name_body . (!empty($this->file_dst_name_ext) ? '.' . $this->file_dst_name_ext : '');
3283. $cpt++;
3284. $this->file_dst_pathname = $this->file_dst_path . $this->file_dst_name;
3285. }
3286. if ($cpt>1) $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;auto_rename to ' . $this->file_dst_name . '<br />';
3287. }
3289. $this->log .= '- destination file details<br />';
3290. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_dst_name : ' . $this->file_dst_name . '<br />';
3291. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;file_dst_pathname : ' . $this->file_dst_pathname . '<br />';
3293. if ($this->file_overwrite) {
3294. $this->log .= '- no overwrite checking<br />';
3295. } else {
3296. if (@file_exists($this->file_dst_pathname)) {
3297. $this->processed = false;
3298. $this->error = $this->translate('already_exists', array($this->file_dst_name));
3299. } else {
3300. $this->log .= '- ' . $this->file_dst_name . ' doesn\'t exist already<br />';
3301. }
3302. }
3303. }
3304. }
3306. if ($this->processed) {
3307. // if we have already moved the uploaded file, we use the temporary copy as source file, and check if it exists
3308. if (!empty($this->file_src_temp)) {
3309. $this->log .= '- use the temp file instead of the original file since it is a second process<br />';
3310. $this->file_src_pathname = $this->file_src_temp;
3311. if (!file_exists($this->file_src_pathname)) {
3312. $this->processed = false;
3313. $this->error = $this->translate('temp_file_missing');
3314. }
3315. // if we haven't a temp file, and that we do check on uploads, we use is_uploaded_file()
3316. } else if (!$this->no_upload_check) {
3317. if (!is_uploaded_file($this->file_src_pathname)) {
3318. $this->processed = false;
3319. $this->error = $this->translate('source_missing');
3320. }
3321. // otherwise, if we don't check on uploaded files (local file for instance), we use file_exists()
3322. } else {
3323. if (!file_exists($this->file_src_pathname)) {
3324. $this->processed = false;
3325. $this->error = $this->translate('source_missing');
3326. }
3327. }
3329. // checks if the destination directory exists, and attempt to create it
3330. if (!$return_mode) {
3331. if ($this->processed && !file_exists($this->file_dst_path)) {
3332. if ($this->dir_auto_create) {
3333. $this->log .= '- ' . $this->file_dst_path . ' doesn\'t exist. Attempting creation:';
3334. if (!$this->rmkdir($this->file_dst_path, $this->dir_chmod)) {
3335. $this->log .= ' failed<br />';
3336. $this->processed = false;
3337. $this->error = $this->translate('destination_dir');
3338. } else {
3339. $this->log .= ' success<br />';
3340. }
3341. } else {
3342. $this->error = $this->translate('destination_dir_missing');
3343. }
3344. }
3346. if ($this->processed && !is_dir($this->file_dst_path)) {
3347. $this->processed = false;
3348. $this->error = $this->translate('destination_path_not_dir');
3349. }
3351. // checks if the destination directory is writeable, and attempt to make it writeable
3352. $hash = md5($this->file_dst_name_body . rand(1, 1000));
3353. if ($this->processed && !($f = @fopen($this->file_dst_path . $hash . '.' . $this->file_dst_name_ext, 'a+'))) {
3354. if ($this->dir_auto_chmod) {
3355. $this->log .= '- ' . $this->file_dst_path . ' is not writeable. Attempting chmod:';
3356. if (!@chmod($this->file_dst_path, $this->dir_chmod)) {
3357. $this->log .= ' failed<br />';
3358. $this->processed = false;
3359. $this->error = $this->translate('destination_dir_write');
3360. } else {
3361. $this->log .= ' success<br />';
3362. if (!($f = @fopen($this->file_dst_path . $hash . '.' . $this->file_dst_name_ext, 'a+'))) { // we re-check
3363. $this->processed = false;
3364. $this->error = $this->translate('destination_dir_write');
3365. } else {
3366. @fclose($f);
3367. }
3368. }
3369. } else {
3370. $this->processed = false;
3371. $this->error = $this->translate('destination_path_write');
3372. }
3373. } else {
3374. if ($this->processed) @fclose($f);
3375. @unlink($this->file_dst_path . $hash . '.' . $this->file_dst_name_ext);
3376. }
3379. // if we have an uploaded file, and if it is the first process, and if we can't access the file directly (open_basedir restriction)
3380. // then we create a temp file that will be used as the source file in subsequent processes
3381. // the third condition is there to check if the file is not accessible *directly* (it already has positively gone through is_uploaded_file(), so it exists)
3382. if (!$this->no_upload_check && empty($this->file_src_temp) && !@file_exists($this->file_src_pathname)) {
3383. $this->log .= '- attempting to use a temp file:';
3384. $hash = md5($this->file_dst_name_body . rand(1, 1000));
3385. if (move_uploaded_file($this->file_src_pathname, $this->file_dst_path . $hash . '.' . $this->file_dst_name_ext)) {
3386. $this->file_src_pathname = $this->file_dst_path . $hash . '.' . $this->file_dst_name_ext;
3387. $this->file_src_temp = $this->file_src_pathname;
3388. $this->log .= ' file created<br />';
3389. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;temp file is: ' . $this->file_src_temp . '<br />';
3390. } else {
3391. $this->log .= ' failed<br />';
3392. $this->processed = false;
3393. $this->error = $this->translate('temp_file');
3394. }
3395. }
3396. }
3397. }
3399. if ($this->processed) {
3401. // we do a quick check to ensure the file is really an image
3402. // we can do this only now, as it would have failed before in case of open_basedir
3403. if ($image_manipulation && !@getimagesize($this->file_src_pathname)) {
3404. $this->log .= '- the file is not an image!<br />';
3405. $image_manipulation = false;
3406. }
3408. if ($image_manipulation) {
3410. // checks if the source file is readable
3411. if ($this->processed && !($f = @fopen($this->file_src_pathname, 'r'))) {
3412. $this->processed = false;
3413. $this->error = $this->translate('source_not_readable');
3414. } else {
3415. @fclose($f);
3416. }
3418. // we now do all the image manipulations
3419. $this->log .= '- image resizing or conversion wanted<br />';
3420. if ($this->gdversion()) {
3421. switch($this->image_src_type) {
3422. case 'jpg':
3423. if (!function_exists('imagecreatefromjpeg')) {
3424. $this->processed = false;
3425. $this->error = $this->translate('no_create_support', array('JPEG'));
3426. } else {
3427. $image_src = @imagecreatefromjpeg($this->file_src_pathname);
3428. if (!$image_src) {
3429. $this->processed = false;
3430. $this->error = $this->translate('create_error', array('JPEG'));
3431. } else {
3432. $this->log .= '- source image is JPEG<br />';
3433. }
3434. }
3435. break;
3436. case 'png':
3437. if (!function_exists('imagecreatefrompng')) {
3438. $this->processed = false;
3439. $this->error = $this->translate('no_create_support', array('PNG'));
3440. } else {
3441. $image_src = @imagecreatefrompng($this->file_src_pathname);
3442. if (!$image_src) {
3443. $this->processed = false;
3444. $this->error = $this->translate('create_error', array('PNG'));
3445. } else {
3446. $this->log .= '- source image is PNG<br />';
3447. }
3448. }
3449. break;
3450. case 'gif':
3451. if (!function_exists('imagecreatefromgif')) {
3452. $this->processed = false;
3453. $this->error = $this->translate('no_create_support', array('GIF'));
3454. } else {
3455. $image_src = @imagecreatefromgif($this->file_src_pathname);
3456. if (!$image_src) {
3457. $this->processed = false;
3458. $this->error = $this->translate('create_error', array('GIF'));
3459. } else {
3460. $this->log .= '- source image is GIF<br />';
3461. }
3462. }
3463. break;
3464. case 'bmp':
3465. if (!method_exists($this, 'imagecreatefrombmp')) {
3466. $this->processed = false;
3467. $this->error = $this->translate('no_create_support', array('BMP'));
3468. } else {
3469. $image_src = @$this->imagecreatefrombmp($this->file_src_pathname);
3470. if (!$image_src) {
3471. $this->processed = false;
3472. $this->error = $this->translate('create_error', array('BMP'));
3473. } else {
3474. $this->log .= '- source image is BMP<br />';
3475. }
3476. }
3477. break;
3478. default:
3479. $this->processed = false;
3480. $this->error = $this->translate('source_invalid');
3481. }
3482. } else {
3483. $this->processed = false;
3484. $this->error = $this->translate('gd_missing');
3485. }
3487. if ($this->processed && $image_src) {
3489. // we have to set image_convert if it is not already
3490. if (empty($this->image_convert)) {
3491. $this->log .= '- setting destination file type to ' . $this->file_src_name_ext . '<br />';
3492. $this->image_convert = $this->file_src_name_ext;
3493. }
3495. if (!in_array($this->image_convert, $this->image_supported)) {
3496. $this->image_convert = 'jpg';
3497. }
3499. // we set the default color to be the background color if we don't output in a transparent format
3500. if ($this->image_convert != 'png' && $this->image_convert != 'gif' && !empty($this->image_default_color) && empty($this->image_background_color)) $this->image_background_color = $this->image_default_color;
3501. if (!empty($this->image_background_color)) $this->image_default_color = $this->image_background_color;
3502. if (empty($this->image_default_color)) $this->image_default_color = '#FFFFFF';
3504. $this->image_src_x = imagesx($image_src);
3505. $this->image_src_y = imagesy($image_src);
3506. $gd_version = $this->gdversion();
3507. $ratio_crop = null;
3509. if (!imageistruecolor($image_src)) { // $this->image_src_type == 'gif'
3510. $this->log .= '- image is detected as having a palette<br />';
3511. $this->image_is_palette = true;
3512. $this->image_transparent_color = imagecolortransparent($image_src);
3513. if ($this->image_transparent_color >= 0 && imagecolorstotal($image_src) > $this->image_transparent_color) {
3514. $this->image_is_transparent = true;
3515. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;palette image is detected as transparent<br />';
3516. }
3517. // if the image has a palette (GIF), we convert it to true color, preserving transparency
3518. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;convert palette image to true color<br />';
3519. $true_color = imagecreatetruecolor($this->image_src_x, $this->image_src_y);
3520. imagealphablending($true_color, false);
3521. imagesavealpha($true_color, true);
3522. for ($x = 0; $x < $this->image_src_x; $x++) {
3523. for ($y = 0; $y < $this->image_src_y; $y++) {
3524. if ($this->image_transparent_color >= 0 && imagecolorat($image_src, $x, $y) == $this->image_transparent_color) {
3525. imagesetpixel($true_color, $x, $y, 127 << 24);
3526. } else {
3527. $rgb = imagecolorsforindex($image_src, imagecolorat($image_src, $x, $y));
3528. imagesetpixel($true_color, $x, $y, ($rgb['alpha'] << 24) | ($rgb['red'] << 16) | ($rgb['green'] << 8) | $rgb['blue']);
3529. }
3530. }
3531. }
3532. $image_src = $this->imagetransfer($true_color, $image_src);
3533. imagealphablending($image_src, false);
3534. imagesavealpha($image_src, true);
3535. $this->image_is_palette = false;
3536. }
3539. $image_dst = & $image_src;
3541. // pre-crop image, before resizing
3542. if ((!empty($this->image_precrop))) {
3543. if (is_array($this->image_precrop)) {
3544. $vars = $this->image_precrop;
3545. } else {
3546. $vars = explode(' ', $this->image_precrop);
3547. }
3548. if (sizeof($vars) == 4) {
3549. $ct = $vars[0]; $cr = $vars[1]; $cb = $vars[2]; $cl = $vars[3];
3550. } else if (sizeof($vars) == 2) {
3551. $ct = $vars[0]; $cr = $vars[1]; $cb = $vars[0]; $cl = $vars[1];
3552. } else {
3553. $ct = $vars[0]; $cr = $vars[0]; $cb = $vars[0]; $cl = $vars[0];
3554. }
3555. if (strpos($ct, '%')>0) $ct = $this->image_src_y * (str_replace('%','',$ct) / 100);
3556. if (strpos($cr, '%')>0) $cr = $this->image_src_x * (str_replace('%','',$cr) / 100);
3557. if (strpos($cb, '%')>0) $cb = $this->image_src_y * (str_replace('%','',$cb) / 100);
3558. if (strpos($cl, '%')>0) $cl = $this->image_src_x * (str_replace('%','',$cl) / 100);
3559. if (strpos($ct, 'px')>0) $ct = str_replace('px','',$ct);
3560. if (strpos($cr, 'px')>0) $cr = str_replace('px','',$cr);
3561. if (strpos($cb, 'px')>0) $cb = str_replace('px','',$cb);
3562. if (strpos($cl, 'px')>0) $cl = str_replace('px','',$cl);
3563. $ct = (int) $ct;
3564. $cr = (int) $cr;
3565. $cb = (int) $cb;
3566. $cl = (int) $cl;
3567. $this->log .= '- pre-crop image : ' . $ct . ' ' . $cr . ' ' . $cb . ' ' . $cl . ' <br />';
3568. $this->image_src_x = $this->image_src_x - $cl - $cr;
3569. $this->image_src_y = $this->image_src_y - $ct - $cb;
3570. if ($this->image_src_x < 1) $this->image_src_x = 1;
3571. if ($this->image_src_y < 1) $this->image_src_y = 1;
3572. $tmp = $this->imagecreatenew($this->image_src_x, $this->image_src_y);
3574. // we copy the image into the recieving image
3575. imagecopy($tmp, $image_dst, 0, 0, $cl, $ct, $this->image_src_x, $this->image_src_y);
3577. // if we crop with negative margins, we have to make sure the extra bits are the right color, or transparent
3578. if ($ct < 0 || $cr < 0 || $cb < 0 || $cl < 0 ) {
3579. // use the background color if present
3580. if (!empty($this->image_background_color)) {
3581. list($red, $green, $blue) = $this->getcolors($this->image_background_color);
3582. $fill = imagecolorallocate($tmp, $red, $green, $blue);
3583. } else {
3584. $fill = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
3585. }
3586. // fills eventual negative margins
3587. if ($ct < 0) imagefilledrectangle($tmp, 0, 0, $this->image_src_x, -$ct, $fill);
3588. if ($cr < 0) imagefilledrectangle($tmp, $this->image_src_x + $cr, 0, $this->image_src_x, $this->image_src_y, $fill);
3589. if ($cb < 0) imagefilledrectangle($tmp, 0, $this->image_src_y + $cb, $this->image_src_x, $this->image_src_y, $fill);
3590. if ($cl < 0) imagefilledrectangle($tmp, 0, 0, -$cl, $this->image_src_y, $fill);
3591. }
3593. // we transfert tmp into image_dst
3594. $image_dst = $this->imagetransfer($tmp, $image_dst);
3595. }
3597. // resize image (and move image_src_x, image_src_y dimensions into image_dst_x, image_dst_y)
3598. if ($this->image_resize) {
3599. $this->log .= '- resizing...<br />';
3601. if ($this->image_ratio_x) {
3602. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;calculate x size<br />';
3603. $this->image_dst_x = round(($this->image_src_x * $this->image_y) / $this->image_src_y);
3604. $this->image_dst_y = $this->image_y;
3605. } else if ($this->image_ratio_y) {
3606. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;calculate y size<br />';
3607. $this->image_dst_x = $this->image_x;
3608. $this->image_dst_y = round(($this->image_src_y * $this->image_x) / $this->image_src_x);
3609. } else if (is_numeric($this->image_ratio_pixels)) {
3610. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;calculate x/y size to match a number of pixels<br />';
3611. $pixels = $this->image_src_y * $this->image_src_x;
3612. $diff = sqrt($this->image_ratio_pixels / $pixels);
3613. $this->image_dst_x = round($this->image_src_x * $diff);
3614. $this->image_dst_y = round($this->image_src_y * $diff);
3615. } else if ($this->image_ratio || $this->image_ratio_crop || $this->image_ratio_fill || $this->image_ratio_no_zoom_in || $this->image_ratio_no_zoom_out) {
3616. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;check x/y sizes<br />';
3617. if ((!$this->image_ratio_no_zoom_in && !$this->image_ratio_no_zoom_out)
3618. || ($this->image_ratio_no_zoom_in && ($this->image_src_x > $this->image_x || $this->image_src_y > $this->image_y))
3619. || ($this->image_ratio_no_zoom_out && $this->image_src_x < $this->image_x && $this->image_src_y < $this->image_y)) {
3620. $this->image_dst_x = $this->image_x;
3621. $this->image_dst_y = $this->image_y;
3622. if ($this->image_ratio_crop) {
3623. if (!is_string($this->image_ratio_crop)) $this->image_ratio_crop = '';
3624. $this->image_ratio_crop = strtolower($this->image_ratio_crop);
3625. if (($this->image_src_x/$this->image_x) > ($this->image_src_y/$this->image_y)) {
3626. $this->image_dst_y = $this->image_y;
3627. $this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y));
3628. $ratio_crop = array();
3629. $ratio_crop['x'] = $this->image_dst_x - $this->image_x;
3630. if (strpos($this->image_ratio_crop, 'l') !== false) {
3631. $ratio_crop['l'] = 0;
3632. $ratio_crop['r'] = $ratio_crop['x'];
3633. } else if (strpos($this->image_ratio_crop, 'r') !== false) {
3634. $ratio_crop['l'] = $ratio_crop['x'];
3635. $ratio_crop['r'] = 0;
3636. } else {
3637. $ratio_crop['l'] = round($ratio_crop['x']/2);
3638. $ratio_crop['r'] = $ratio_crop['x'] - $ratio_crop['l'];
3639. }
3640. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;ratio_crop_x : ' . $ratio_crop['x'] . ' (' . $ratio_crop['l'] . ';' . $ratio_crop['r'] . ')<br />';
3641. if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
3642. } else {
3643. $this->image_dst_x = $this->image_x;
3644. $this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x));
3645. $ratio_crop = array();
3646. $ratio_crop['y'] = $this->image_dst_y - $this->image_y;
3647. if (strpos($this->image_ratio_crop, 't') !== false) {
3648. $ratio_crop['t'] = 0;
3649. $ratio_crop['b'] = $ratio_crop['y'];
3650. } else if (strpos($this->image_ratio_crop, 'b') !== false) {
3651. $ratio_crop['t'] = $ratio_crop['y'];
3652. $ratio_crop['b'] = 0;
3653. } else {
3654. $ratio_crop['t'] = round($ratio_crop['y']/2);
3655. $ratio_crop['b'] = $ratio_crop['y'] - $ratio_crop['t'];
3656. }
3657. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;ratio_crop_y : ' . $ratio_crop['y'] . ' (' . $ratio_crop['t'] . ';' . $ratio_crop['b'] . ')<br />';
3658. if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
3659. }
3660. } else if ($this->image_ratio_fill) {
3661. if (!is_string($this->image_ratio_fill)) $this->image_ratio_fill = '';
3662. $this->image_ratio_fill = strtolower($this->image_ratio_fill);
3663. if (($this->image_src_x/$this->image_x) < ($this->image_src_y/$this->image_y)) {
3664. $this->image_dst_y = $this->image_y;
3665. $this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y));
3666. $ratio_crop = array();
3667. $ratio_crop['x'] = $this->image_dst_x - $this->image_x;
3668. if (strpos($this->image_ratio_fill, 'l') !== false) {
3669. $ratio_crop['l'] = 0;
3670. $ratio_crop['r'] = $ratio_crop['x'];
3671. } else if (strpos($this->image_ratio_fill, 'r') !== false) {
3672. $ratio_crop['l'] = $ratio_crop['x'];
3673. $ratio_crop['r'] = 0;
3674. } else {
3675. $ratio_crop['l'] = round($ratio_crop['x']/2);
3676. $ratio_crop['r'] = $ratio_crop['x'] - $ratio_crop['l'];
3677. }
3678. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;ratio_fill_x : ' . $ratio_crop['x'] . ' (' . $ratio_crop['l'] . ';' . $ratio_crop['r'] . ')<br />';
3679. if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
3680. } else {
3681. $this->image_dst_x = $this->image_x;
3682. $this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x));
3683. $ratio_crop = array();
3684. $ratio_crop['y'] = $this->image_dst_y - $this->image_y;
3685. if (strpos($this->image_ratio_fill, 't') !== false) {
3686. $ratio_crop['t'] = 0;
3687. $ratio_crop['b'] = $ratio_crop['y'];
3688. } else if (strpos($this->image_ratio_fill, 'b') !== false) {
3689. $ratio_crop['t'] = $ratio_crop['y'];
3690. $ratio_crop['b'] = 0;
3691. } else {
3692. $ratio_crop['t'] = round($ratio_crop['y']/2);
3693. $ratio_crop['b'] = $ratio_crop['y'] - $ratio_crop['t'];
3694. }
3695. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;ratio_fill_y : ' . $ratio_crop['y'] . ' (' . $ratio_crop['t'] . ';' . $ratio_crop['b'] . ')<br />';
3696. if (is_null($this->image_crop)) $this->image_crop = array(0, 0, 0, 0);
3697. }
3698. } else {
3699. if (($this->image_src_x/$this->image_x) > ($this->image_src_y/$this->image_y)) {
3700. $this->image_dst_x = $this->image_x;
3701. $this->image_dst_y = intval($this->image_src_y*($this->image_x / $this->image_src_x));
3702. } else {
3703. $this->image_dst_y = $this->image_y;
3704. $this->image_dst_x = intval($this->image_src_x*($this->image_y / $this->image_src_y));
3705. }
3706. }
3707. } else {
3708. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;doesn\'t calculate x/y sizes<br />';
3709. $this->image_dst_x = $this->image_src_x;
3710. $this->image_dst_y = $this->image_src_y;
3711. }
3712. } else {
3713. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;use plain sizes<br />';
3714. $this->image_dst_x = $this->image_x;
3715. $this->image_dst_y = $this->image_y;
3716. }
3718. if ($this->image_dst_x < 1) $this->image_dst_x = 1;
3719. if ($this->image_dst_y < 1) $this->image_dst_y = 1;
3720. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
3722. if ($gd_version >= 2) {
3723. $res = imagecopyresampled($tmp, $image_src, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_src_x, $this->image_src_y);
3724. } else {
3725. $res = imagecopyresized($tmp, $image_src, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_src_x, $this->image_src_y);
3726. }
3728. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;resized image object created<br />';
3729. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image_src_x y : ' . $this->image_src_x . ' x ' . $this->image_src_y . '<br />';
3730. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image_dst_x y : ' . $this->image_dst_x . ' x ' . $this->image_dst_y . '<br />';
3731. // we transfert tmp into image_dst
3732. $image_dst = $this->imagetransfer($tmp, $image_dst);
3734. } else {
3735. $this->image_dst_x = $this->image_src_x;
3736. $this->image_dst_y = $this->image_src_y;
3737. }
3739. // crop image (and also crops if image_ratio_crop is used)
3740. if ((!empty($this->image_crop) || !is_null($ratio_crop))) {
3741. if (is_array($this->image_crop)) {
3742. $vars = $this->image_crop;
3743. } else {
3744. $vars = explode(' ', $this->image_crop);
3745. }
3746. if (sizeof($vars) == 4) {
3747. $ct = $vars[0]; $cr = $vars[1]; $cb = $vars[2]; $cl = $vars[3];
3748. } else if (sizeof($vars) == 2) {
3749. $ct = $vars[0]; $cr = $vars[1]; $cb = $vars[0]; $cl = $vars[1];
3750. } else {
3751. $ct = $vars[0]; $cr = $vars[0]; $cb = $vars[0]; $cl = $vars[0];
3752. }
3753. if (strpos($ct, '%')>0) $ct = $this->image_dst_y * (str_replace('%','',$ct) / 100);
3754. if (strpos($cr, '%')>0) $cr = $this->image_dst_x * (str_replace('%','',$cr) / 100);
3755. if (strpos($cb, '%')>0) $cb = $this->image_dst_y * (str_replace('%','',$cb) / 100);
3756. if (strpos($cl, '%')>0) $cl = $this->image_dst_x * (str_replace('%','',$cl) / 100);
3757. if (strpos($ct, 'px')>0) $ct = str_replace('px','',$ct);
3758. if (strpos($cr, 'px')>0) $cr = str_replace('px','',$cr);
3759. if (strpos($cb, 'px')>0) $cb = str_replace('px','',$cb);
3760. if (strpos($cl, 'px')>0) $cl = str_replace('px','',$cl);
3761. $ct = (int) $ct;
3762. $cr = (int) $cr;
3763. $cb = (int) $cb;
3764. $cl = (int) $cl;
3765. // we adjust the cropping if we use image_ratio_crop
3766. if (!is_null($ratio_crop)) {
3767. if (array_key_exists('t', $ratio_crop)) $ct += $ratio_crop['t'];
3768. if (array_key_exists('r', $ratio_crop)) $cr += $ratio_crop['r'];
3769. if (array_key_exists('b', $ratio_crop)) $cb += $ratio_crop['b'];
3770. if (array_key_exists('l', $ratio_crop)) $cl += $ratio_crop['l'];
3771. }
3772. $this->log .= '- crop image : ' . $ct . ' ' . $cr . ' ' . $cb . ' ' . $cl . ' <br />';
3773. $this->image_dst_x = $this->image_dst_x - $cl - $cr;
3774. $this->image_dst_y = $this->image_dst_y - $ct - $cb;
3775. if ($this->image_dst_x < 1) $this->image_dst_x = 1;
3776. if ($this->image_dst_y < 1) $this->image_dst_y = 1;
3777. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
3779. // we copy the image into the recieving image
3780. imagecopy($tmp, $image_dst, 0, 0, $cl, $ct, $this->image_dst_x, $this->image_dst_y);
3782. // if we crop with negative margins, we have to make sure the extra bits are the right color, or transparent
3783. if ($ct < 0 || $cr < 0 || $cb < 0 || $cl < 0 ) {
3784. // use the background color if present
3785. if (!empty($this->image_background_color)) {
3786. list($red, $green, $blue) = $this->getcolors($this->image_background_color);
3787. $fill = imagecolorallocate($tmp, $red, $green, $blue);
3788. } else {
3789. $fill = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
3790. }
3791. // fills eventual negative margins
3792. if ($ct < 0) imagefilledrectangle($tmp, 0, 0, $this->image_dst_x, -$ct, $fill);
3793. if ($cr < 0) imagefilledrectangle($tmp, $this->image_dst_x + $cr, 0, $this->image_dst_x, $this->image_dst_y, $fill);
3794. if ($cb < 0) imagefilledrectangle($tmp, 0, $this->image_dst_y + $cb, $this->image_dst_x, $this->image_dst_y, $fill);
3795. if ($cl < 0) imagefilledrectangle($tmp, 0, 0, -$cl, $this->image_dst_y, $fill);
3796. }
3798. // we transfert tmp into image_dst
3799. $image_dst = $this->imagetransfer($tmp, $image_dst);
3800. }
3802. // flip image
3803. if ($gd_version >= 2 && !empty($this->image_flip)) {
3804. $this->image_flip = strtolower($this->image_flip);
3805. $this->log .= '- flip image : ' . $this->image_flip . '<br />';
3806. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
3807. for ($x = 0; $x < $this->image_dst_x; $x++) {
3808. for ($y = 0; $y < $this->image_dst_y; $y++){
3809. if (strpos($this->image_flip, 'v') !== false) {
3810. imagecopy($tmp, $image_dst, $this->image_dst_x - $x - 1, $y, $x, $y, 1, 1);
3811. } else {
3812. imagecopy($tmp, $image_dst, $x, $this->image_dst_y - $y - 1, $x, $y, 1, 1);
3813. }
3814. }
3815. }
3816. // we transfert tmp into image_dst
3817. $image_dst = $this->imagetransfer($tmp, $image_dst);
3818. }
3820. // rotate image
3821. if ($gd_version >= 2 && is_numeric($this->image_rotate)) {
3822. if (!in_array($this->image_rotate, array(0, 90, 180, 270))) $this->image_rotate = 0;
3823. if ($this->image_rotate != 0) {
3824. if ($this->image_rotate == 90 || $this->image_rotate == 270) {
3825. $tmp = $this->imagecreatenew($this->image_dst_y, $this->image_dst_x);
3826. } else {
3827. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
3828. }
3829. $this->log .= '- rotate image : ' . $this->image_rotate . '<br />';
3830. for ($x = 0; $x < $this->image_dst_x; $x++) {
3831. for ($y = 0; $y < $this->image_dst_y; $y++){
3832. if ($this->image_rotate == 90) {
3833. imagecopy($tmp, $image_dst, $y, $x, $x, $this->image_dst_y - $y - 1, 1, 1);
3834. } else if ($this->image_rotate == 180) {
3835. imagecopy($tmp, $image_dst, $x, $y, $this->image_dst_x - $x - 1, $this->image_dst_y - $y - 1, 1, 1);
3836. } else if ($this->image_rotate == 270) {
3837. imagecopy($tmp, $image_dst, $y, $x, $this->image_dst_x - $x - 1, $y, 1, 1);
3838. } else {
3839. imagecopy($tmp, $image_dst, $x, $y, $x, $y, 1, 1);
3840. }
3841. }
3842. }
3843. if ($this->image_rotate == 90 || $this->image_rotate == 270) {
3844. $t = $this->image_dst_y;
3845. $this->image_dst_y = $this->image_dst_x;
3846. $this->image_dst_x = $t;
3847. }
3848. // we transfert tmp into image_dst
3849. $image_dst = $this->imagetransfer($tmp, $image_dst);
3850. }
3851. }
3853. // add color overlay
3854. if ($gd_version >= 2 && (is_numeric($this->image_overlay_percent) && $this->image_overlay_percent > 0 && !empty($this->image_overlay_color))) {
3855. $this->log .= '- apply color overlay<br />';
3856. list($red, $green, $blue) = $this->getcolors($this->image_overlay_color);
3857. $filter = imagecreatetruecolor($this->image_dst_x, $this->image_dst_y);
3858. $color = imagecolorallocate($filter, $red, $green, $blue);
3859. imagefilledrectangle($filter, 0, 0, $this->image_dst_x, $this->image_dst_y, $color);
3860. $this->imagecopymergealpha($image_dst, $filter, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y, $this->image_overlay_percent);
3861. imagedestroy($filter);
3862. }
3864. // add brightness, contrast and tint, turns to greyscale and inverts colors
3865. if ($gd_version >= 2 && ($this->image_negative || $this->image_greyscale || is_numeric($this->image_threshold)|| is_numeric($this->image_brightness) || is_numeric($this->image_contrast) || !empty($this->image_tint_color))) {
3866. $this->log .= '- apply tint, light, contrast correction, negative, greyscale and threshold<br />';
3867. if (!empty($this->image_tint_color)) list($tint_red, $tint_green, $tint_blue) = $this->getcolors($this->image_tint_color);
3868. imagealphablending($image_dst, true);
3869. for($y=0; $y < $this->image_dst_y; $y++) {
3870. for($x=0; $x < $this->image_dst_x; $x++) {
3871. if ($this->image_greyscale) {
3872. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
3873. $r = $g = $b = round((0.2125 * $pixel['red']) + (0.7154 * $pixel['green']) + (0.0721 * $pixel['blue']));
3874. $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
3875. imagesetpixel($image_dst, $x, $y, $color);
3876. }
3877. if (is_numeric($this->image_threshold)) {
3878. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
3879. $c = (round($pixel['red'] + $pixel['green'] + $pixel['blue']) / 3) - 127;
3880. $r = $g = $b = ($c > $this->image_threshold ? 255 : 0);
3881. $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
3882. imagesetpixel($image_dst, $x, $y, $color);
3883. }
3884. if (is_numeric($this->image_brightness)) {
3885. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
3886. $r = max(min(round($pixel['red'] + (($this->image_brightness * 2))), 255), 0);
3887. $g = max(min(round($pixel['green'] + (($this->image_brightness * 2))), 255), 0);
3888. $b = max(min(round($pixel['blue'] + (($this->image_brightness * 2))), 255), 0);
3889. $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
3890. imagesetpixel($image_dst, $x, $y, $color);
3891. }
3892. if (is_numeric($this->image_contrast)) {
3893. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
3894. $r = max(min(round(($this->image_contrast + 128) * $pixel['red'] / 128), 255), 0);
3895. $g = max(min(round(($this->image_contrast + 128) * $pixel['green'] / 128), 255), 0);
3896. $b = max(min(round(($this->image_contrast + 128) * $pixel['blue'] / 128), 255), 0);
3897. $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
3898. imagesetpixel($image_dst, $x, $y, $color);
3899. }
3900. if (!empty($this->image_tint_color)) {
3901. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
3902. $r = min(round($tint_red * $pixel['red'] / 169), 255);
3903. $g = min(round($tint_green * $pixel['green'] / 169), 255);
3904. $b = min(round($tint_blue * $pixel['blue'] / 169), 255);
3905. $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
3906. imagesetpixel($image_dst, $x, $y, $color);
3907. }
3908. if (!empty($this->image_negative)) {
3909. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
3910. $r = round(255 - $pixel['red']);
3911. $g = round(255 - $pixel['green']);
3912. $b = round(255 - $pixel['blue']);
3913. $color = imagecolorallocatealpha($image_dst, $r, $g, $b, $pixel['alpha']);
3914. imagesetpixel($image_dst, $x, $y, $color);
3915. }
3916. }
3917. }
3918. }
3920. // adds a border
3921. if ($gd_version >= 2 && !empty($this->image_border)) {
3922. if (is_array($this->image_border)) {
3923. $vars = $this->image_border;
3924. $this->log .= '- add border : ' . implode(' ', $this->image_border) . '<br />';
3925. } else {
3926. $this->log .= '- add border : ' . $this->image_border . '<br />';
3927. $vars = explode(' ', $this->image_border);
3928. }
3929. if (sizeof($vars) == 4) {
3930. $ct = $vars[0]; $cr = $vars[1]; $cb = $vars[2]; $cl = $vars[3];
3931. } else if (sizeof($vars) == 2) {
3932. $ct = $vars[0]; $cr = $vars[1]; $cb = $vars[0]; $cl = $vars[1];
3933. } else {
3934. $ct = $vars[0]; $cr = $vars[0]; $cb = $vars[0]; $cl = $vars[0];
3935. }
3936. if (strpos($ct, '%')>0) $ct = $this->image_dst_y * (str_replace('%','',$ct) / 100);
3937. if (strpos($cr, '%')>0) $cr = $this->image_dst_x * (str_replace('%','',$cr) / 100);
3938. if (strpos($cb, '%')>0) $cb = $this->image_dst_y * (str_replace('%','',$cb) / 100);
3939. if (strpos($cl, '%')>0) $cl = $this->image_dst_x * (str_replace('%','',$cl) / 100);
3940. if (strpos($ct, 'px')>0) $ct = str_replace('px','',$ct);
3941. if (strpos($cr, 'px')>0) $cr = str_replace('px','',$cr);
3942. if (strpos($cb, 'px')>0) $cb = str_replace('px','',$cb);
3943. if (strpos($cl, 'px')>0) $cl = str_replace('px','',$cl);
3944. $ct = (int) $ct;
3945. $cr = (int) $cr;
3946. $cb = (int) $cb;
3947. $cl = (int) $cl;
3948. $this->image_dst_x = $this->image_dst_x + $cl + $cr;
3949. $this->image_dst_y = $this->image_dst_y + $ct + $cb;
3950. if (!empty($this->image_border_color)) list($red, $green, $blue) = $this->getcolors($this->image_border_color);
3951. // we now create an image, that we fill with the border color
3952. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
3953. $background = imagecolorallocatealpha($tmp, $red, $green, $blue, 0);
3954. imagefilledrectangle($tmp, 0, 0, $this->image_dst_x, $this->image_dst_y, $background);
3955. // we then copy the source image into the new image, without merging so that only the border is actually kept
3956. imagecopy($tmp, $image_dst, $cl, $ct, 0, 0, $this->image_dst_x - $cr - $cl, $this->image_dst_y - $cb - $ct);
3957. // we transfert tmp into image_dst
3958. $image_dst = $this->imagetransfer($tmp, $image_dst);
3959. }
3961. // add frame border
3962. if (is_numeric($this->image_frame)) {
3963. if (is_array($this->image_frame_colors)) {
3964. $vars = $this->image_frame_colors;
3965. $this->log .= '- add frame : ' . implode(' ', $this->image_frame_colors) . '<br />';
3966. } else {
3967. $this->log .= '- add frame : ' . $this->image_frame_colors . '<br />';
3968. $vars = explode(' ', $this->image_frame_colors);
3969. }
3970. $nb = sizeof($vars);
3971. $this->image_dst_x = $this->image_dst_x + ($nb * 2);
3972. $this->image_dst_y = $this->image_dst_y + ($nb * 2);
3973. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
3974. imagecopy($tmp, $image_dst, $nb, $nb, 0, 0, $this->image_dst_x - ($nb * 2), $this->image_dst_y - ($nb * 2));
3975. for ($i=0; $i<$nb; $i++) {
3976. list($red, $green, $blue) = $this->getcolors($vars[$i]);
3977. $c = imagecolorallocate($tmp, $red, $green, $blue);
3978. if ($this->image_frame == 1) {
3979. imageline($tmp, $i, $i, $this->image_dst_x - $i -1, $i, $c);
3980. imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i -1, $this->image_dst_x - $i -1, $i, $c);
3981. imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i -1, $i, $this->image_dst_y - $i -1, $c);
3982. imageline($tmp, $i, $i, $i, $this->image_dst_y - $i -1, $c);
3983. } else {
3984. imageline($tmp, $i, $i, $this->image_dst_x - $i -1, $i, $c);
3985. imageline($tmp, $this->image_dst_x - $nb + $i, $this->image_dst_y - $nb + $i, $this->image_dst_x - $nb + $i, $nb - $i, $c);
3986. imageline($tmp, $this->image_dst_x - $nb + $i, $this->image_dst_y - $nb + $i, $nb - $i, $this->image_dst_y - $nb + $i, $c);
3987. imageline($tmp, $i, $i, $i, $this->image_dst_y - $i -1, $c);
3988. }
3989. }
3990. // we transfert tmp into image_dst
3991. $image_dst = $this->imagetransfer($tmp, $image_dst);
3992. }
3994. // add bevel border
3995. if ($this->image_bevel > 0) {
3996. if (empty($this->image_bevel_color1)) $this->image_bevel_color1 = '#FFFFFF';
3997. if (empty($this->image_bevel_color2)) $this->image_bevel_color2 = '#000000';
3998. list($red1, $green1, $blue1) = $this->getcolors($this->image_bevel_color1);
3999. list($red2, $green2, $blue2) = $this->getcolors($this->image_bevel_color2);
4000. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y);
4001. imagecopy($tmp, $image_dst, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y);
4002. imagealphablending($tmp, true);
4003. for ($i=0; $i<$this->image_bevel; $i++) {
4004. $alpha = round(($i / $this->image_bevel) * 127);
4005. $c1 = imagecolorallocatealpha($tmp, $red1, $green1, $blue1, $alpha);
4006. $c2 = imagecolorallocatealpha($tmp, $red2, $green2, $blue2, $alpha);
4007. imageline($tmp, $i, $i, $this->image_dst_x - $i -1, $i, $c1);
4008. imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i, $this->image_dst_x - $i -1, $i, $c2);
4009. imageline($tmp, $this->image_dst_x - $i -1, $this->image_dst_y - $i -1, $i, $this->image_dst_y - $i -1, $c2);
4010. imageline($tmp, $i, $i, $i, $this->image_dst_y - $i -1, $c1);
4011. }
4012. // we transfert tmp into image_dst
4013. $image_dst = $this->imagetransfer($tmp, $image_dst);
4014. }
4016. // add watermark image
4017. if ($this->image_watermark!='' && file_exists($this->image_watermark)) {
4018. $this->log .= '- add watermark<br />';
4019. $this->image_watermark_position = strtolower($this->image_watermark_position);
4020. $watermark_info = getimagesize($this->image_watermark);
4021. $watermark_type = (array_key_exists(2, $watermark_info) ? $watermark_info[2] : null); // 1 = GIF, 2 = JPG, 3 = PNG
4022. $watermark_checked = false;
4023. if ($watermark_type == IMAGETYPE_GIF) {
4024. if (!function_exists('imagecreatefromgif')) {
4025. $this->error = $this->translate('watermark_no_create_support', array('GIF'));
4026. } else {
4027. $filter = @imagecreatefromgif($this->image_watermark);
4028. if (!$filter) {
4029. $this->error = $this->translate('watermark_create_error', array('GIF'));
4030. } else {
4031. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;watermark source image is GIF<br />';
4032. $watermark_checked = true;
4033. }
4034. }
4035. } else if ($watermark_type == IMAGETYPE_JPEG) {
4036. if (!function_exists('imagecreatefromjpeg')) {
4037. $this->error = $this->translate('watermark_no_create_support', array('JPEG'));
4038. } else {
4039. $filter = @imagecreatefromjpeg($this->image_watermark);
4040. if (!$filter) {
4041. $this->error = $this->translate('watermark_create_error', array('JPEG'));
4042. } else {
4043. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;watermark source image is JPEG<br />';
4044. $watermark_checked = true;
4045. }
4046. }
4047. } else if ($watermark_type == IMAGETYPE_PNG) {
4048. if (!function_exists('imagecreatefrompng')) {
4049. $this->error = $this->translate('watermark_no_create_support', array('PNG'));
4050. } else {
4051. $filter = @imagecreatefrompng($this->image_watermark);
4052. if (!$filter) {
4053. $this->error = $this->translate('watermark_create_error', array('PNG'));
4054. } else {
4055. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;watermark source image is PNG<br />';
4056. $watermark_checked = true;
4057. }
4058. }
4059. } else if ($watermark_type == IMAGETYPE_BMP) {
4060. if (!method_exists($this, 'imagecreatefrombmp')) {
4061. $this->error = $this->translate('watermark_no_create_support', array('BMP'));
4062. } else {
4063. $filter = @$this->imagecreatefrombmp($this->image_watermark);
4064. if (!$filter) {
4065. $this->error = $this->translate('watermark_create_error', array('BMP'));
4066. } else {
4067. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;watermark source image is BMP<br />';
4068. $watermark_checked = true;
4069. }
4070. }
4071. } else {
4072. $this->error = $this->translate('watermark_invalid');
4073. }
4074. if ($watermark_checked) {
4075. $watermark_width = imagesx($filter);
4076. $watermark_height = imagesy($filter);
4077. $watermark_x = 0;
4078. $watermark_y = 0;
4079. if (is_numeric($this->image_watermark_x)) {
4080. if ($this->image_watermark_x < 0) {
4081. $watermark_x = $this->image_dst_x - $watermark_width + $this->image_watermark_x;
4082. } else {
4083. $watermark_x = $this->image_watermark_x;
4084. }
4085. } else {
4086. if (strpos($this->image_watermark_position, 'r') !== false) {
4087. $watermark_x = $this->image_dst_x - $watermark_width;
4088. } else if (strpos($this->image_watermark_position, 'l') !== false) {
4089. $watermark_x = 0;
4090. } else {
4091. $watermark_x = ($this->image_dst_x - $watermark_width) / 2;
4092. }
4093. }
4094. if (is_numeric($this->image_watermark_y)) {
4095. if ($this->image_watermark_y < 0) {
4096. $watermark_y = $this->image_dst_y - $watermark_height + $this->image_watermark_y;
4097. } else {
4098. $watermark_y = $this->image_watermark_y;
4099. }
4100. } else {
4101. if (strpos($this->image_watermark_position, 'b') !== false) {
4102. $watermark_y = $this->image_dst_y - $watermark_height;
4103. } else if (strpos($this->image_watermark_position, 't') !== false) {
4104. $watermark_y = 0;
4105. } else {
4106. $watermark_y = ($this->image_dst_y - $watermark_height) / 2;
4107. }
4108. }
4109. imagecopyresampled ($image_dst, $filter, $watermark_x, $watermark_y, 0, 0, $watermark_width, $watermark_height, $watermark_width, $watermark_height);
4110. } else {
4111. $this->error = $this->translate('watermark_invalid');
4112. }
4113. }
4115. // add text
4116. if (!empty($this->image_text)) {
4117. $this->log .= '- add text<br />';
4119. // calculate sizes in human readable format
4120. $src_size = $this->file_src_size / 1024;
4121. $src_size_mb = number_format($src_size / 1024, 1, ".", " ");
4122. $src_size_kb = number_format($src_size, 1, ".", " ");
4123. $src_size_human = ($src_size > 1024 ? $src_size_mb . " MB" : $src_size_kb . " kb");
4125. $this->image_text = str_replace(
4126. array('[src_name]',
4127. '[src_name_body]',
4128. '[src_name_ext]',
4129. '[src_pathname]',
4130. '[src_mime]',
4131. '[src_size]',
4132. '[src_size_kb]',
4133. '[src_size_mb]',
4134. '[src_size_human]',
4135. '[src_x]',
4136. '[src_y]',
4137. '[src_pixels]',
4138. '[src_type]',
4139. '[src_bits]',
4140. '[dst_path]',
4141. '[dst_name_body]',
4142. '[dst_name_ext]',
4143. '[dst_name]',
4144. '[dst_pathname]',
4145. '[dst_x]',
4146. '[dst_y]',
4147. '[date]',
4148. '[time]',
4149. '[host]',
4150. '[server]',
4151. '[ip]',
4152. '[gd_version]'),
4153. array($this->file_src_name,
4154. $this->file_src_name_body,
4155. $this->file_src_name_ext,
4156. $this->file_src_pathname,
4157. $this->file_src_mime,
4158. $this->file_src_size,
4159. $src_size_kb,
4160. $src_size_mb,
4161. $src_size_human,
4162. $this->image_src_x,
4163. $this->image_src_y,
4164. $this->image_src_pixels,
4165. $this->image_src_type,
4166. $this->image_src_bits,
4167. $this->file_dst_path,
4168. $this->file_dst_name_body,
4169. $this->file_dst_name_ext,
4170. $this->file_dst_name,
4171. $this->file_dst_pathname,
4172. $this->image_dst_x,
4173. $this->image_dst_y,
4174. date('Y-m-d'),
4175. date('H:i:s'),
4176. (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'n/a'),
4177. (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'n/a'),
4178. (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'n/a'),
4179. $this->gdversion(true)),
4180. $this->image_text);
4182. if (!is_numeric($this->image_text_padding)) $this->image_text_padding = 0;
4183. if (!is_numeric($this->image_text_line_spacing)) $this->image_text_line_spacing = 0;
4184. if (!is_numeric($this->image_text_padding_x)) $this->image_text_padding_x = $this->image_text_padding;
4185. if (!is_numeric($this->image_text_padding_y)) $this->image_text_padding_y = $this->image_text_padding;
4186. $this->image_text_position = strtolower($this->image_text_position);
4187. $this->image_text_direction = strtolower($this->image_text_direction);
4188. $this->image_text_alignment = strtolower($this->image_text_alignment);
4190. // if the font is a string, we assume that we might want to load a font
4191. if (!is_numeric($this->image_text_font) && strlen($this->image_text_font) > 4 && substr(strtolower($this->image_text_font), -4) == '.gdf') {
4192. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;try to load font ' . $this->image_text_font . '... ';
4193. if ($this->image_text_font = @imageloadfont($this->image_text_font)) {
4194. $this->log .= 'success<br />';
4195. } else {
4196. $this->log .= 'error<br />';
4197. $this->image_text_font = 5;
4198. }
4199. }
4201. $text = explode("\n", $this->image_text);
4202. $char_width = imagefontwidth($this->image_text_font);
4203. $char_height = imagefontheight($this->image_text_font);
4204. $text_height = 0;
4205. $text_width = 0;
4206. $line_height = 0;
4207. $line_width = 0;
4209. foreach ($text as $k => $v) {
4210. if ($this->image_text_direction == 'v') {
4211. $h = ($char_width * strlen($v));
4212. if ($h > $text_height) $text_height = $h;
4213. $line_width = $char_height;
4214. $text_width += $line_width + ($k < (sizeof($text)-1) ? $this->image_text_line_spacing : 0);
4215. } else {
4216. $w = ($char_width * strlen($v));
4217. if ($w > $text_width) $text_width = $w;
4218. $line_height = $char_height;
4219. $text_height += $line_height + ($k < (sizeof($text)-1) ? $this->image_text_line_spacing : 0);
4220. }
4221. }
4222. $text_width += (2 * $this->image_text_padding_x);
4223. $text_height += (2 * $this->image_text_padding_y);
4224. $text_x = 0;
4225. $text_y = 0;
4226. if (is_numeric($this->image_text_x)) {
4227. if ($this->image_text_x < 0) {
4228. $text_x = $this->image_dst_x - $text_width + $this->image_text_x;
4229. } else {
4230. $text_x = $this->image_text_x;
4231. }
4232. } else {
4233. if (strpos($this->image_text_position, 'r') !== false) {
4234. $text_x = $this->image_dst_x - $text_width;
4235. } else if (strpos($this->image_text_position, 'l') !== false) {
4236. $text_x = 0;
4237. } else {
4238. $text_x = ($this->image_dst_x - $text_width) / 2;
4239. }
4240. }
4241. if (is_numeric($this->image_text_y)) {
4242. if ($this->image_text_y < 0) {
4243. $text_y = $this->image_dst_y - $text_height + $this->image_text_y;
4244. } else {
4245. $text_y = $this->image_text_y;
4246. }
4247. } else {
4248. if (strpos($this->image_text_position, 'b') !== false) {
4249. $text_y = $this->image_dst_y - $text_height;
4250. } else if (strpos($this->image_text_position, 't') !== false) {
4251. $text_y = 0;
4252. } else {
4253. $text_y = ($this->image_dst_y - $text_height) / 2;
4254. }
4255. }
4257. // add a background, maybe transparent
4258. if (!empty($this->image_text_background)) {
4259. list($red, $green, $blue) = $this->getcolors($this->image_text_background);
4260. if ($gd_version >= 2 && (is_numeric($this->image_text_background_percent)) && $this->image_text_background_percent >= 0 && $this->image_text_background_percent <= 100) {
4261. $filter = imagecreatetruecolor($text_width, $text_height);
4262. $background_color = imagecolorallocate($filter, $red, $green, $blue);
4263. imagefilledrectangle($filter, 0, 0, $text_width, $text_height, $background_color);
4264. $this->imagecopymergealpha($image_dst, $filter, $text_x, $text_y, 0, 0, $text_width, $text_height, $this->image_text_background_percent);
4265. imagedestroy($filter);
4266. } else {
4267. $background_color = imagecolorallocate($image_dst ,$red, $green, $blue);
4268. imagefilledrectangle($image_dst, $text_x, $text_y, $text_x + $text_width, $text_y + $text_height, $background_color);
4269. }
4270. }
4272. $text_x += $this->image_text_padding_x;
4273. $text_y += $this->image_text_padding_y;
4274. $t_width = $text_width - (2 * $this->image_text_padding_x);
4275. $t_height = $text_height - (2 * $this->image_text_padding_y);
4276. list($red, $green, $blue) = $this->getcolors($this->image_text_color);
4278. // add the text, maybe transparent
4279. if ($gd_version >= 2 && (is_numeric($this->image_text_percent)) && $this->image_text_percent >= 0 && $this->image_text_percent <= 100) {
4280. if ($t_width < 0) $t_width = 0;
4281. if ($t_height < 0) $t_height = 0;
4282. $filter = $this->imagecreatenew($t_width, $t_height, false, true);
4283. $text_color = imagecolorallocate($filter ,$red, $green, $blue);
4285. foreach ($text as $k => $v) {
4286. if ($this->image_text_direction == 'v') {
4287. imagestringup($filter,
4288. $this->image_text_font,
4289. $k * ($line_width + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)),
4290. $text_height - (2 * $this->image_text_padding_y) - ($this->image_text_alignment == 'l' ? 0 : (($t_height - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))) ,
4291. $v,
4292. $text_color);
4293. } else {
4294. imagestring($filter,
4295. $this->image_text_font,
4296. ($this->image_text_alignment == 'l' ? 0 : (($t_width - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))),
4297. $k * ($line_height + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)),
4298. $v,
4299. $text_color);
4300. }
4301. }
4302. $this->imagecopymergealpha($image_dst, $filter, $text_x, $text_y, 0, 0, $t_width, $t_height, $this->image_text_percent);
4303. imagedestroy($filter);
4305. } else {
4306. $text_color = imageColorAllocate($image_dst ,$red, $green, $blue);
4307. foreach ($text as $k => $v) {
4308. if ($this->image_text_direction == 'v') {
4309. imagestringup($image_dst,
4310. $this->image_text_font,
4311. $text_x + $k * ($line_width + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)),
4312. $text_y + $text_height - (2 * $this->image_text_padding_y) - ($this->image_text_alignment == 'l' ? 0 : (($t_height - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))),
4313. $v,
4314. $text_color);
4315. } else {
4316. imagestring($image_dst,
4317. $this->image_text_font,
4318. $text_x + ($this->image_text_alignment == 'l' ? 0 : (($t_width - strlen($v) * $char_width) / ($this->image_text_alignment == 'r' ? 1 : 2))),
4319. $text_y + $k * ($line_height + ($k > 0 && $k < (sizeof($text)) ? $this->image_text_line_spacing : 0)),
4320. $v,
4321. $text_color);
4322. }
4323. }
4324. }
4325. }
4327. // add a reflection
4328. if ($this->image_reflection_height) {
4329. $this->log .= '- add reflection : ' . $this->image_reflection_height . '<br />';
4330. // we decode image_reflection_height, which can be a integer, a string in pixels or percentage
4331. $image_reflection_height = $this->image_reflection_height;
4332. if (strpos($image_reflection_height, '%')>0) $image_reflection_height = $this->image_dst_y * (str_replace('%','',$image_reflection_height / 100));
4333. if (strpos($image_reflection_height, 'px')>0) $image_reflection_height = str_replace('px','',$image_reflection_height);
4334. $image_reflection_height = (int) $image_reflection_height;
4335. if ($image_reflection_height > $this->image_dst_y) $image_reflection_height = $this->image_dst_y;
4336. if (empty($this->image_reflection_opacity)) $this->image_reflection_opacity = 60;
4337. // create the new destination image
4338. $tmp = $this->imagecreatenew($this->image_dst_x, $this->image_dst_y + $image_reflection_height + $this->image_reflection_space, true);
4339. $transparency = $this->image_reflection_opacity;
4341. // copy the original image
4342. imagecopy($tmp, $image_dst, 0, 0, 0, 0, $this->image_dst_x, $this->image_dst_y + ($this->image_reflection_space < 0 ? $this->image_reflection_space : 0));
4344. // we have to make sure the extra bit is the right color, or transparent
4345. if ($image_reflection_height + $this->image_reflection_space > 0) {
4346. // use the background color if present
4347. if (!empty($this->image_background_color)) {
4348. list($red, $green, $blue) = $this->getcolors($this->image_background_color);
4349. $fill = imagecolorallocate($tmp, $red, $green, $blue);
4350. } else {
4351. $fill = imagecolorallocatealpha($tmp, 0, 0, 0, 127);
4352. }
4353. // fill in from the edge of the extra bit
4354. imagefill($tmp, round($this->image_dst_x / 2), $this->image_dst_y + $image_reflection_height + $this->image_reflection_space - 1, $fill);
4355. }
4357. // copy the reflection
4358. for ($y = 0; $y < $image_reflection_height; $y++) {
4359. for ($x = 0; $x < $this->image_dst_x; $x++) {
4360. $pixel_b = imagecolorsforindex($tmp, imagecolorat($tmp, $x, $y + $this->image_dst_y + $this->image_reflection_space));
4361. $pixel_o = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $this->image_dst_y - $y - 1 + ($this->image_reflection_space < 0 ? $this->image_reflection_space : 0)));
4362. $alpha_o = 1 - ($pixel_o['alpha'] / 127);
4363. $alpha_b = 1 - ($pixel_b['alpha'] / 127);
4364. $opacity = $alpha_o * $transparency / 100;
4365. if ($opacity > 0) {
4366. $red = round((($pixel_o['red'] * $opacity) + ($pixel_b['red'] ) * $alpha_b) / ($alpha_b + $opacity));
4367. $green = round((($pixel_o['green'] * $opacity) + ($pixel_b['green']) * $alpha_b) / ($alpha_b + $opacity));
4368. $blue = round((($pixel_o['blue'] * $opacity) + ($pixel_b['blue'] ) * $alpha_b) / ($alpha_b + $opacity));
4369. $alpha = ($opacity + $alpha_b);
4370. if ($alpha > 1) $alpha = 1;
4371. $alpha = round((1 - $alpha) * 127);
4372. $color = imagecolorallocatealpha($tmp, $red, $green, $blue, $alpha);
4373. imagesetpixel($tmp, $x, $y + $this->image_dst_y + $this->image_reflection_space, $color);
4374. }
4375. }
4376. if ($transparency > 0) $transparency = $transparency - ($this->image_reflection_opacity / $image_reflection_height);
4377. }
4379. // copy the resulting image into the destination image
4380. $this->image_dst_y = $this->image_dst_y + $image_reflection_height + $this->image_reflection_space;
4381. $image_dst = $this->imagetransfer($tmp, $image_dst);
4382. }
4384. // reduce the JPEG image to a set desired size
4385. if (is_numeric($this->jpeg_size) && $this->jpeg_size > 0 && ($this->image_convert == 'jpeg' || $this->image_convert == 'jpg')) {
4386. // inspired by: JPEGReducer class version 1, 25 November 2004, Author: Huda M ElMatsani, justhuda at netscape dot net
4387. $this->log .= '- JPEG desired file size : ' . $this->jpeg_size . '<br />';
4388. // calculate size of each image. 75%, 50%, and 25% quality
4389. ob_start(); imagejpeg($image_dst,'',75); $buffer = ob_get_contents(); ob_end_clean();
4390. $size75 = strlen($buffer);
4391. ob_start(); imagejpeg($image_dst,'',50); $buffer = ob_get_contents(); ob_end_clean();
4392. $size50 = strlen($buffer);
4393. ob_start(); imagejpeg($image_dst,'',25); $buffer = ob_get_contents(); ob_end_clean();
4394. $size25 = strlen($buffer);
4396. // calculate gradient of size reduction by quality
4397. $mgrad1 = 25 / ($size50-$size25);
4398. $mgrad2 = 25 / ($size75-$size50);
4399. $mgrad3 = 50 / ($size75-$size25);
4400. $mgrad = ($mgrad1 + $mgrad2 + $mgrad3) / 3;
4401. // result of approx. quality factor for expected size
4402. $q_factor = round($mgrad * ($this->jpeg_size - $size50) + 50);
4404. if ($q_factor<1) {
4405. $this->jpeg_quality=1;
4406. } elseif ($q_factor>100) {
4407. $this->jpeg_quality=100;
4408. } else {
4409. $this->jpeg_quality=$q_factor;
4410. }
4411. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;JPEG quality factor set to ' . $this->jpeg_quality . '<br />';
4412. }
4414. // converts image from true color, and fix transparency if needed
4415. $this->log .= '- converting...<br />';
4416. switch($this->image_convert) {
4417. case 'gif':
4418. // if the image is true color, we convert it to a palette
4419. if (imageistruecolor($image_dst)) {
4420. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;true color to palette<br />';
4421. // creates a black and white mask
4422. $mask = array(array());
4423. for ($x = 0; $x < $this->image_dst_x; $x++) {
4424. for ($y = 0; $y < $this->image_dst_y; $y++) {
4425. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
4426. $mask[$x][$y] = $pixel['alpha'];
4427. }
4428. }
4429. list($red, $green, $blue) = $this->getcolors($this->image_default_color);
4430. // first, we merge the image with the background color, so we know which colors we will have
4431. for ($x = 0; $x < $this->image_dst_x; $x++) {
4432. for ($y = 0; $y < $this->image_dst_y; $y++) {
4433. if ($mask[$x][$y] > 0){
4434. // we have some transparency. we combine the color with the default color
4435. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
4436. $alpha = ($mask[$x][$y] / 127);
4437. $pixel['red'] = round(($pixel['red'] * (1 -$alpha) + $red * ($alpha)));
4438. $pixel['green'] = round(($pixel['green'] * (1 -$alpha) + $green * ($alpha)));
4439. $pixel['blue'] = round(($pixel['blue'] * (1 -$alpha) + $blue * ($alpha)));
4440. $color = imagecolorallocate($image_dst, $pixel['red'], $pixel['green'], $pixel['blue']);
4441. imagesetpixel($image_dst, $x, $y, $color);
4442. }
4443. }
4444. }
4445. // transfrom the true color image into palette, with it merged default color in
4446. // we will have the best color possible, including the background
4447. if (empty($this->image_background_color)) {
4448. imagetruecolortopalette($image_dst, true, 255);
4449. $transparency = imagecolorallocate($image_dst, 254, 1, 253);
4450. imagecolortransparent($image_dst, $transparency);
4451. // make the transparent areas transparent
4452. for ($x = 0; $x < $this->image_dst_x; $x++) {
4453. for ($y = 0; $y < $this->image_dst_y; $y++) {
4454. // we test wether we have enough opacity to justify keeping the color
4455. if ($mask[$x][$y] > 120) imagesetpixel($image_dst, $x, $y, $transparency);
4456. }
4457. }
4458. }
4459. unset($mask);
4460. }
4461. break;
4462. case 'jpg':
4463. case 'bmp':
4464. // if the image doesn't support any transparency, then we merge it with the default color
4465. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;fills in transparency with default color<br />';
4466. list($red, $green, $blue) = $this->getcolors($this->image_default_color);
4467. $transparency = imagecolorallocate($image_dst, $red, $green, $blue);
4468. // make the transaparent areas transparent
4469. for ($x = 0; $x < $this->image_dst_x; $x++) {
4470. for ($y = 0; $y < $this->image_dst_y; $y++) {
4471. // we test wether we have some transparency, in which case we will merge the colors
4472. if (imageistruecolor($image_dst)) {
4473. $rgba = imagecolorat($image_dst, $x, $y);
4474. $pixel = array('red' => ($rgba >> 16) & 0xFF,
4475. 'green' => ($rgba >> 8) & 0xFF,
4476. 'blue' => $rgba & 0xFF,
4477. 'alpha' => ($rgba & 0x7F000000) >> 24);
4478. } else {
4479. $pixel = imagecolorsforindex($image_dst, imagecolorat($image_dst, $x, $y));
4480. }
4481. if ($pixel['alpha'] == 127) {
4482. // we have full transparency. we make the pixel transparent
4483. imagesetpixel($image_dst, $x, $y, $transparency);
4484. } else if ($pixel['alpha'] > 0) {
4485. // we have some transparency. we combine the color with the default color
4486. $alpha = ($pixel['alpha'] / 127);
4487. $pixel['red'] = round(($pixel['red'] * (1 -$alpha) + $red * ($alpha)));
4488. $pixel['green'] = round(($pixel['green'] * (1 -$alpha) + $green * ($alpha)));
4489. $pixel['blue'] = round(($pixel['blue'] * (1 -$alpha) + $blue * ($alpha)));
4490. $color = imagecolorclosest($image_dst, $pixel['red'], $pixel['green'], $pixel['blue']);
4491. imagesetpixel($image_dst, $x, $y, $color);
4492. }
4493. }
4494. }
4496. break;
4497. default:
4498. break;
4499. }
4501. // outputs image
4502. $this->log .= '- saving image...<br />';
4503. switch($this->image_convert) {
4504. case 'jpeg':
4505. case 'jpg':
4506. if (!$return_mode) {
4507. $result = @imagejpeg($image_dst, $this->file_dst_pathname, $this->jpeg_quality);
4508. } else {
4509. ob_start();
4510. $result = @imagejpeg($image_dst, '', $this->jpeg_quality);
4511. $return_content = ob_get_contents();
4512. ob_end_clean();
4513. }
4514. if (!$result) {
4515. $this->processed = false;
4516. $this->error = $this->translate('file_create', array('JPEG'));
4517. } else {
4518. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;JPEG image created<br />';
4519. }
4520. break;
4521. case 'png':
4522. imagealphablending( $image_dst, false );
4523. imagesavealpha( $image_dst, true );
4524. if (!$return_mode) {
4525. $result = @imagepng($image_dst, $this->file_dst_pathname);
4526. } else {
4527. ob_start();
4528. $result = @imagepng($image_dst);
4529. $return_content = ob_get_contents();
4530. ob_end_clean();
4531. }
4532. if (!$result) {
4533. $this->processed = false;
4534. $this->error = $this->translate('file_create', array('PNG'));
4535. } else {
4536. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;PNG image created<br />';
4537. }
4538. break;
4539. case 'gif':
4540. if (!$return_mode) {
4541. $result = @imagegif($image_dst, $this->file_dst_pathname);
4542. } else {
4543. ob_start();
4544. $result = @imagegif($image_dst);
4545. $return_content = ob_get_contents();
4546. ob_end_clean();
4547. }
4548. if (!$result) {
4549. $this->processed = false;
4550. $this->error = $this->translate('file_create', array('GIF'));
4551. } else {
4552. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;GIF image created<br />';
4553. }
4554. break;
4555. case 'bmp':
4556. if (!$return_mode) {
4557. $result = $this->imagebmp($image_dst, $this->file_dst_pathname);
4558. } else {
4559. ob_start();
4560. $result = $this->imagebmp($image_dst);
4561. $return_content = ob_get_contents();
4562. ob_end_clean();
4563. }
4564. if (!$result) {
4565. $this->processed = false;
4566. $this->error = $this->translate('file_create', array('BMP'));
4567. } else {
4568. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;BMP image created<br />';
4569. }
4570. break;
4572. default:
4573. $this->processed = false;
4574. $this->error = $this->translate('no_conversion_type');
4575. }
4576. if ($this->processed) {
4577. if (is_resource($image_src)) imagedestroy($image_src);
4578. if (is_resource($image_dst)) imagedestroy($image_dst);
4579. $this->log .= '&nbsp;&nbsp;&nbsp;&nbsp;image objects destroyed<br />';
4580. }
4581. }
4583. } else {
4584. $this->log .= '- no image processing wanted<br />';
4586. if (!$return_mode) {
4587. // copy the file to its final destination. we don't use move_uploaded_file here
4588. // if we happen to have open_basedir restrictions, it is a temp file that we copy, not the original uploaded file
4589. if (!copy($this->file_src_pathname, $this->file_dst_pathname)) {
4590. $this->processed = false;
4591. $this->error = $this->translate('copy_failed');
4592. }
4593. } else {
4594. // returns the file, so that its content can be received by the caller
4595. $return_content = @file_get_contents($this->file_src_pathname);
4596. if ($return_content === FALSE) {
4597. $this->processed = false;
4598. $this->error = $this->translate('reading_failed');
4599. }
4600. }
4601. }
4602. }
4604. if ($this->processed) {
4605. $this->log .= '- <b>process OK</b><br />';
4606. } else {
4607. $this->log .= '- <b>error</b>: ' . $this->error . '<br />';
4608. }
4610. // we reinit all the vars
4611. $this->init();
4613. // we may return the image content
4614. if ($return_mode) return $return_content;
4616. }
4618. /**
4619. * Deletes the uploaded file from its temporary location
4620. *
4621. * When PHP uploads a file, it stores it in a temporary location.
4622. * When you {@link process} the file, you actually copy the resulting file to the given location, it doesn't alter the original file.
4623. * Once you have processed the file as many times as you wanted, you can delete the uploaded file.
4624. * If there is open_basedir restrictions, the uploaded file is in fact a temporary file
4625. *
4626. * You might want not to use this function if you work on local files, as it will delete the source file
4627. *
4628. * @access public
4629. */
4630. function clean() {
4631. $this->log .= '<b>cleanup</b><br />';
4632. $this->log .= '- delete temp file ' . $this->file_src_pathname . '<br />';
4633. @unlink($this->file_src_pathname);
4634. }
4637. /**
4638. * Opens a BMP image
4639. *
4640. * This function has been written by DHKold, and is used with permission of the author
4641. *
4642. * @access public
4643. */
4644. function imagecreatefrombmp($filename) {
4645. if (! $f1 = fopen($filename,"rb")) return false;
4647. $file = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
4648. if ($file['file_type'] != 19778) return false;
4650. $bmp = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
4651. '/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
4652. '/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
4653. $bmp['colors'] = pow(2,$bmp['bits_per_pixel']);
4654. if ($bmp['size_bitmap'] == 0) $bmp['size_bitmap'] = $file['file_size'] - $file['bitmap_offset'];
4655. $bmp['bytes_per_pixel'] = $bmp['bits_per_pixel']/8;
4656. $bmp['bytes_per_pixel2'] = ceil($bmp['bytes_per_pixel']);
4657. $bmp['decal'] = ($bmp['width']*$bmp['bytes_per_pixel']/4);
4658. $bmp['decal'] -= floor($bmp['width']*$bmp['bytes_per_pixel']/4);
4659. $bmp['decal'] = 4-(4*$bmp['decal']);
4660. if ($bmp['decal'] == 4) $bmp['decal'] = 0;
4662. $palette = array();
4663. if ($bmp['colors'] < 16777216) {
4664. $palette = unpack('V'.$bmp['colors'], fread($f1,$bmp['colors']*4));
4665. }
4667. $im = fread($f1,$bmp['size_bitmap']);
4668. $vide = chr(0);
4670. $res = imagecreatetruecolor($bmp['width'],$bmp['height']);
4671. $P = 0;
4672. $Y = $bmp['height']-1;
4673. while ($Y >= 0) {
4674. $X=0;
4675. while ($X < $bmp['width']) {
4676. if ($bmp['bits_per_pixel'] == 24)
4677. $color = unpack("V",substr($im,$P,3).$vide);
4678. elseif ($bmp['bits_per_pixel'] == 16) {
4679. $color = unpack("n",substr($im,$P,2));
4680. $color[1] = $palette[$color[1]+1];
4681. } elseif ($bmp['bits_per_pixel'] == 8) {
4682. $color = unpack("n",$vide.substr($im,$P,1));
4683. $color[1] = $palette[$color[1]+1];
4684. } elseif ($bmp['bits_per_pixel'] == 4) {
4685. $color = unpack("n",$vide.substr($im,floor($P),1));
4686. if (($P*2)%2 == 0) $color[1] = ($color[1] >> 4) ; else $color[1] = ($color[1] & 0x0F);
4687. $color[1] = $palette[$color[1]+1];
4688. } elseif ($bmp['bits_per_pixel'] == 1) {
4689. $color = unpack("n",$vide.substr($im,floor($P),1));
4690. if (($P*8)%8 == 0) $color[1] = $color[1] >>7;
4691. elseif (($P*8)%8 == 1) $color[1] = ($color[1] & 0x40)>>6;
4692. elseif (($P*8)%8 == 2) $color[1] = ($color[1] & 0x20)>>5;
4693. elseif (($P*8)%8 == 3) $color[1] = ($color[1] & 0x10)>>4;
4694. elseif (($P*8)%8 == 4) $color[1] = ($color[1] & 0x8)>>3;
4695. elseif (($P*8)%8 == 5) $color[1] = ($color[1] & 0x4)>>2;
4696. elseif (($P*8)%8 == 6) $color[1] = ($color[1] & 0x2)>>1;
4697. elseif (($P*8)%8 == 7) $color[1] = ($color[1] & 0x1);
4698. $color[1] = $palette[$color[1]+1];
4699. } else
4700. return FALSE;
4701. imagesetpixel($res,$X,$Y,$color[1]);
4702. $X++;
4703. $P += $bmp['bytes_per_pixel'];
4704. }
4705. $Y--;
4706. $P+=$bmp['decal'];
4707. }
4708. fclose($f1);
4709. return $res;
4710. }
4712. /**
4713. * Saves a BMP image
4714. *
4715. * This function has been published on the PHP website, and can be used freely
4716. *
4717. * @access public
4718. */
4719. function imagebmp(&$im, $filename = "") {
4721. if (!$im) return false;
4722. $w = imagesx($im);
4723. $h = imagesy($im);
4724. $result = '';
4726. // if the image is not true color, we convert it first
4727. if (!imageistruecolor($im)) {
4728. $tmp = imagecreatetruecolor($w, $h);
4729. imagecopy($tmp, $im, 0, 0, 0, 0, $w, $h);
4730. imagedestroy($im);
4731. $im = & $tmp;
4732. }
4734. $biBPLine = $w * 3;
4735. $biStride = ($biBPLine + 3) & ~3;
4736. $biSizeImage = $biStride * $h;
4737. $bfOffBits = 54;
4738. $bfSize = $bfOffBits + $biSizeImage;
4740. $result .= substr('BM', 0, 2);
4741. $result .= pack ('VvvV', $bfSize, 0, 0, $bfOffBits);
4742. $result .= pack ('VVVvvVVVVVV', 40, $w, $h, 1, 24, 0, $biSizeImage, 0, 0, 0, 0);
4744. $numpad = $biStride - $biBPLine;
4745. for ($y = $h - 1; $y >= 0; --$y) {
4746. for ($x = 0; $x < $w; ++$x) {
4747. $col = imagecolorat ($im, $x, $y);
4748. $result .= substr(pack ('V', $col), 0, 3);
4749. }
4750. for ($i = 0; $i < $numpad; ++$i)
4751. $result .= pack ('C', 0);
4752. }
4754. if($filename==""){
4755. echo $result;
4756. } else {
4757. $file = fopen($filename, "wb");
4758. fwrite($file, $result);
4759. fclose($file);
4760. }
4761. return true;
4762. }
4763. }
4765. ?>