1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @name OpenImporter |
4
|
|
|
* @copyright OpenImporter contributors |
5
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
6
|
|
|
* |
7
|
|
|
* @version 1.0 Alpha |
8
|
|
|
* |
9
|
|
|
* This file contains code based on: |
10
|
|
|
* |
11
|
|
|
* Simple Machines Forum (SMF) |
12
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
13
|
|
|
* license: BSD, See included LICENSE.TXT for terms and conditions. |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Checks if we've passed a time limit.. |
18
|
|
|
* |
19
|
|
|
* @param int|null $substep |
20
|
|
|
* @param int $stop_time |
21
|
|
|
* |
22
|
|
|
* @return null |
23
|
|
|
*/ |
24
|
|
|
function pastTime($substep = null, $stop_time = 5) |
25
|
|
|
{ |
26
|
|
|
global $oi_import, $time_start; |
27
|
|
|
|
28
|
|
|
if (isset($_GET['substep']) && $_GET['substep'] < $substep) |
29
|
|
|
{ |
30
|
|
|
$_GET['substep'] = $substep; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
// Some details for our progress bar |
34
|
|
|
if (isset($oi_import->count->$substep) && $oi_import->count->$substep > 0 && isset($_REQUEST['start']) && $_REQUEST['start'] > 0 && isset($substep)) |
35
|
|
|
{ |
36
|
|
|
$bar = round($_REQUEST['start'] / $oi_import->count->$substep * 100, 0); |
37
|
|
|
} |
38
|
|
|
else |
39
|
|
|
{ |
40
|
|
|
$bar = false; |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
@set_time_limit(300); |
44
|
|
|
if (is_callable('apache_reset_timeout')) |
45
|
|
|
{ |
46
|
|
|
apache_reset_timeout(); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
if (time() - $time_start < $stop_time) |
50
|
|
|
{ |
51
|
|
|
return; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
// @todo maybe throw an exception? |
55
|
|
|
$oi_import->template->time_limit($bar, $_SESSION['import_progress'], $_SESSION['import_overall']); |
56
|
|
|
$oi_import->template->footer(); |
57
|
|
|
|
58
|
|
|
exit; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Helper function, simple file copy at all |
63
|
|
|
* |
64
|
|
|
* @param string $source |
65
|
|
|
* @param string $destination |
66
|
|
|
* |
67
|
|
|
* @return boolean |
68
|
|
|
*/ |
69
|
|
|
function copy_file($source, $destination) |
70
|
|
|
{ |
71
|
|
|
create_folders_recursive(dirname($destination)); |
72
|
|
|
|
73
|
|
|
if (is_file($source)) |
74
|
|
|
{ |
75
|
|
|
copy($source, $destination); |
76
|
|
|
|
77
|
|
|
return false; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
return true; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
function copy_dir_recursive($source, $destination) |
84
|
|
|
{ |
85
|
|
|
// Create the destination tree |
86
|
|
|
$destination = rtrim($destination, '\\/') . DIRECTORY_SEPARATOR; |
87
|
|
|
create_folders_recursive($destination); |
88
|
|
|
|
89
|
|
|
$source = rtrim($source, '\\/') . DIRECTORY_SEPARATOR; |
90
|
|
|
$dir = opendir($source); |
91
|
|
|
|
92
|
|
|
// If we can't open the directory ... |
93
|
|
|
if ($dir === false) |
94
|
|
|
{ |
95
|
|
|
return; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
while ($file = readdir($dir)) |
99
|
|
|
{ |
100
|
|
|
if ($file == '.' || $file == '..') |
101
|
|
|
{ |
102
|
|
|
continue; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
if (is_dir($source . $file)) |
106
|
|
|
{ |
107
|
|
|
copy_dir_recursive($source . $file, $destination . $file); |
108
|
|
|
} |
109
|
|
|
else |
110
|
|
|
{ |
111
|
|
|
copy($source . $file, $destination . $file); |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Create attachment folders as deep as needed. |
118
|
|
|
* |
119
|
|
|
* @param $path |
120
|
|
|
*/ |
121
|
|
|
function create_folders_recursive($path) |
122
|
|
|
{ |
123
|
|
|
$parent = dirname($path); |
124
|
|
|
|
125
|
|
|
if (!file_exists($parent)) |
126
|
|
|
{ |
127
|
|
|
create_folders_recursive($parent); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
if (!file_exists($path)) |
131
|
|
|
{ |
132
|
|
|
@mkdir($path, 0755); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Add slashes recursively... |
138
|
|
|
* |
139
|
|
|
* @param array $var |
140
|
|
|
* |
141
|
|
|
* @return array |
142
|
|
|
*/ |
143
|
|
|
function addslashes_recursive($var) |
144
|
|
|
{ |
145
|
|
|
if (!is_array($var)) |
146
|
|
|
{ |
147
|
|
|
return addslashes($var); |
148
|
|
|
} |
149
|
|
|
else |
150
|
|
|
{ |
151
|
|
|
foreach ($var as $k => $v) |
152
|
|
|
{ |
153
|
|
|
$var[$k] = addslashes_recursive($v); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
return $var; |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Remove slashes recursively... |
162
|
|
|
* |
163
|
|
|
* @param array $var |
164
|
|
|
* |
165
|
|
|
* @return array |
166
|
|
|
*/ |
167
|
|
|
function stripslashes_recursive($var, $level = 0) |
168
|
|
|
{ |
169
|
|
|
if (!is_array($var)) |
170
|
|
|
{ |
171
|
|
|
return stripslashes($var); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
// Reindex the array without slashes, this time. |
175
|
|
|
$new_var = array(); |
176
|
|
|
|
177
|
|
|
// Strip the slashes from every element. |
178
|
|
|
foreach ($var as $k => $v) |
179
|
|
|
{ |
180
|
|
|
$new_var[stripslashes($k)] = $level > 25 ? null : stripslashes_recursive($v, $level + 1); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
return $new_var; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Copies a directory |
188
|
|
|
* |
189
|
|
|
* @param string $source |
190
|
|
|
* @param string $destination |
191
|
|
|
* |
192
|
|
|
* @return null |
193
|
|
|
*/ |
194
|
|
|
function copy_dir($source, $destination) |
195
|
|
|
{ |
196
|
|
|
if (!is_dir($source) || !($dir = opendir($source))) |
197
|
|
|
{ |
198
|
|
|
return; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
while ($file = readdir($dir)) |
202
|
|
|
{ |
203
|
|
|
if ($file == '.' || $file == '..') |
204
|
|
|
{ |
205
|
|
|
continue; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
// If we have a directory create it on the destination and copy contents into it! |
209
|
|
|
if (is_dir($source . DIRECTORY_SEPARATOR . $file)) |
210
|
|
|
{ |
211
|
|
|
if (!is_dir($destination)) |
212
|
|
|
{ |
213
|
|
|
@mkdir($destination, 0755); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
copy_dir($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file); |
217
|
|
|
} |
218
|
|
|
else |
219
|
|
|
{ |
220
|
|
|
if (!is_dir($destination)) |
221
|
|
|
{ |
222
|
|
|
@mkdir($destination, 0755); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
copy($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file); |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
closedir($dir); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Detects, if a string is utf-8 or not |
233
|
|
|
* |
234
|
|
|
* @param string $string |
235
|
|
|
* |
236
|
|
|
* @return boolean |
237
|
|
|
*/ |
238
|
|
|
function is_utf8($string) |
239
|
|
|
{ |
240
|
|
|
return utf8_encode(utf8_decode($string)) == $string; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Function fix based on ForceUTF8 by Sebastián Grignoli <[email protected]> |
245
|
|
|
* @link http://www.framework2.com.ar/dzone/forceUTF8-es/ |
246
|
|
|
* This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8. |
247
|
|
|
* |
248
|
|
|
* It may fail to convert characters to unicode if they fall into one of these scenarios: |
249
|
|
|
* |
250
|
|
|
* 1) when any of these characters: ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß |
251
|
|
|
* are followed by any of these: ("group B") |
252
|
|
|
* ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶•¸¹º»¼½¾¿ |
253
|
|
|
* For example: %ABREPR%C9SENT%C9%BB. «REPRÉSENTÉ» |
254
|
|
|
* The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB) |
255
|
|
|
* is also a valid unicode character, and will be left unchanged. |
256
|
|
|
* |
257
|
|
|
* 2) when any of these: àáâãäåæçèéêëìíîï are followed by TWO chars from group B, |
258
|
|
|
* 3) when any of these: ðñòó are followed by THREE chars from group B. |
259
|
|
|
* |
260
|
|
|
* @name fix |
261
|
|
|
* |
262
|
|
|
* @param string|string[] $text Any string. |
263
|
|
|
* |
264
|
|
|
* @return string The same string, UTF8 encoded |
265
|
|
|
*/ |
266
|
|
|
function fix_charset($text) |
267
|
|
|
{ |
268
|
|
|
if (is_array($text)) |
269
|
|
|
{ |
270
|
|
|
foreach ($text as $k => $v) |
271
|
|
|
{ |
272
|
|
|
$text[$k] = fix_charset($v); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
return $text; |
276
|
|
|
} |
277
|
|
|
// numeric? There's nothing to do, we simply return our input. |
278
|
|
|
if (is_numeric($text)) |
279
|
|
|
{ |
280
|
|
|
return $text; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
$max = strlen($text); |
284
|
|
|
$buf = ''; |
285
|
|
|
|
286
|
|
|
for ($i = 0; $i < $max; $i++) |
287
|
|
|
{ |
288
|
|
|
$c1 = $text{$i}; |
289
|
|
|
if ($c1 >= "\xc0") |
290
|
|
|
{ |
291
|
|
|
// Should be converted to UTF8, if it's not UTF8 already |
292
|
|
|
$c2 = $i + 1 >= $max ? "\x00" : $text{$i + 1}; |
293
|
|
|
$c3 = $i + 2 >= $max ? "\x00" : $text{$i + 2}; |
294
|
|
|
$c4 = $i + 3 >= $max ? "\x00" : $text{$i + 3}; |
295
|
|
|
if ($c1 >= "\xc0" & $c1 <= "\xdf") |
296
|
|
|
{ |
297
|
|
|
// looks like 2 bytes UTF8 |
298
|
|
|
if ($c2 >= "\x80" && $c2 <= "\xbf") |
299
|
|
|
{ |
300
|
|
|
// yeah, almost sure it's UTF8 already |
301
|
|
|
$buf .= $c1 . $c2; |
302
|
|
|
$i++; |
303
|
|
|
} |
304
|
|
|
else |
305
|
|
|
{ |
306
|
|
|
// not valid UTF8. Convert it. |
307
|
|
|
$cc1 = (chr(ord($c1) / 64) | "\xc0"); |
308
|
|
|
$cc2 = ($c1 & "\x3f") | "\x80"; |
309
|
|
|
$buf .= $cc1 . $cc2; |
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
elseif ($c1 >= "\xe0" & $c1 <= "\xef") |
313
|
|
|
{ |
314
|
|
|
// looks like 3 bytes UTF8 |
315
|
|
|
if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf") |
316
|
|
|
{ |
317
|
|
|
// yeah, almost sure it's UTF8 already |
318
|
|
|
$buf .= $c1 . $c2 . $c3; |
319
|
|
|
$i = $i + 2; |
320
|
|
|
} |
321
|
|
|
else |
322
|
|
|
{ |
323
|
|
|
// not valid UTF8. Convert it. |
324
|
|
|
$cc1 = (chr(ord($c1) / 64) | "\xc0"); |
325
|
|
|
$cc2 = ($c1 & "\x3f") | "\x80"; |
326
|
|
|
$buf .= $cc1 . $cc2; |
327
|
|
|
} |
328
|
|
|
} |
329
|
|
|
elseif ($c1 >= "\xf0" & $c1 <= "\xf7") |
330
|
|
|
{ |
331
|
|
|
// Looks like 4-byte UTF8 |
332
|
|
|
if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf") |
333
|
|
|
{ |
334
|
|
|
// Yeah, almost sure it's UTF8 already |
335
|
|
|
$buf .= $c1 . $c2 . $c3; |
336
|
|
|
$i = $i + 2; |
337
|
|
|
} |
338
|
|
|
else |
339
|
|
|
{ |
340
|
|
|
// Not valid UTF8. Convert it. |
341
|
|
|
$cc1 = (chr(ord($c1) / 64) | "\xc0"); |
342
|
|
|
$cc2 = ($c1 & "\x3f") | "\x80"; |
343
|
|
|
$buf .= $cc1 . $cc2; |
344
|
|
|
} |
345
|
|
|
} |
346
|
|
|
else |
347
|
|
|
{ |
348
|
|
|
// Doesn't look like UTF8, but should be converted |
349
|
|
|
$cc1 = (chr(ord($c1) / 64) | "\xc0"); |
350
|
|
|
$cc2 = (($c1 & "\x3f") | "\x80"); |
351
|
|
|
$buf .= $cc1 . $cc2; |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
elseif (($c1 & "\xc0") == "\x80") |
355
|
|
|
{ |
356
|
|
|
// Needs conversion |
357
|
|
|
$cc1 = (chr(ord($c1) / 64) | "\xc0"); |
358
|
|
|
$cc2 = (($c1 & "\x3f") | "\x80"); |
359
|
|
|
$buf .= $cc1 . $cc2; |
360
|
|
|
} |
361
|
|
|
else |
362
|
|
|
// Doesn't need conversion |
363
|
|
|
{ |
364
|
|
|
$buf .= $c1; |
365
|
|
|
} |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
if (function_exists('mb_decode_numericentity')) |
369
|
|
|
{ |
370
|
|
|
$buf = mb_decode_numericentity($buf, array(0x80, 0x2ffff, 0, 0xffff), 'UTF-8'); |
371
|
|
|
} |
372
|
|
|
else |
373
|
|
|
{ |
374
|
|
|
preg_replace_callback('~(&#(\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'replaceEntities__callback', $buf); |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
// surprise, surprise... the string |
378
|
|
|
return $buf; |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Decode numeric html entities to their UTF8 equivalent character. |
383
|
|
|
* |
384
|
|
|
* What it does: |
385
|
|
|
* - Callback function for preg_replace_callback in subs-members |
386
|
|
|
* - Uses capture group 2 in the supplied array |
387
|
|
|
* - Does basic scan to ensure characters are inside a valid range |
388
|
|
|
* |
389
|
|
|
* @param mixed[] $matches matches from a preg_match_all |
390
|
|
|
* |
391
|
|
|
* @return string $string |
392
|
|
|
*/ |
393
|
|
|
function replaceEntities__callback($matches) |
394
|
|
|
{ |
395
|
|
|
if (!isset($matches[2])) |
396
|
|
|
{ |
397
|
|
|
return ''; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
$num = $matches[2][0] === 'x' ? hexdec(substr($matches[2], 1)) : (int) $matches[2]; |
401
|
|
|
|
402
|
|
|
// Remove left to right / right to left overrides |
403
|
|
|
if ($num === 0x202D || $num === 0x202E) |
404
|
|
|
{ |
405
|
|
|
return ''; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
// Quote, Ampersand, Apostrophe, Less/Greater Than get html replaced |
409
|
|
|
if (in_array($num, array(0x22, 0x26, 0x27, 0x3C, 0x3E))) |
410
|
|
|
{ |
411
|
|
|
return '&#' . $num . ';'; |
412
|
|
|
} |
413
|
|
|
|
414
|
|
|
// <0x20 are control characters, 0x20 is a space, > 0x10FFFF is past the end of the utf8 character set |
415
|
|
|
// 0xD800 >= $num <= 0xDFFF are surrogate markers (not valid for utf8 text) |
416
|
|
|
if ($num < 0x20 || $num > 0x10FFFF || ($num >= 0xD800 && $num <= 0xDFFF)) |
417
|
|
|
{ |
418
|
|
|
return ''; |
419
|
|
|
} |
420
|
|
|
// <0x80 (or less than 128) are standard ascii characters a-z A-Z 0-9 and puncuation |
421
|
|
|
elseif ($num < 0x80) |
422
|
|
|
{ |
423
|
|
|
return chr($num); |
424
|
|
|
} |
425
|
|
|
// <0x800 (2048) |
|
|
|
|
426
|
|
|
elseif ($num < 0x800) |
427
|
|
|
{ |
428
|
|
|
return chr(($num >> 6) + 192) . chr(($num & 63) + 128); |
429
|
|
|
} |
430
|
|
|
// < 0x10000 (65536) |
|
|
|
|
431
|
|
|
elseif ($num < 0x10000) |
432
|
|
|
{ |
433
|
|
|
return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); |
434
|
|
|
} |
435
|
|
|
// <= 0x10FFFF (1114111) |
|
|
|
|
436
|
|
|
else |
437
|
|
|
{ |
438
|
|
|
return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); |
439
|
|
|
} |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
/** |
443
|
|
|
* Helper function for storing vars that need to be global |
444
|
|
|
* |
445
|
|
|
* @param string $variable |
446
|
|
|
* @param string $value |
447
|
|
|
*/ |
448
|
|
|
function store_global($variable, $value) |
449
|
|
|
{ |
450
|
|
|
$_SESSION['store_globals'][$variable] = $value; |
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
/** |
454
|
|
|
* Output some debug information |
455
|
|
|
* |
456
|
|
|
* @param $val |
457
|
|
|
*/ |
458
|
|
|
function print_dbg($val) |
459
|
|
|
{ |
460
|
|
|
echo '<pre>'; |
461
|
|
|
print_r($val); |
462
|
|
|
echo '</pre>'; |
463
|
|
|
} |
464
|
|
|
|
465
|
|
|
/** |
466
|
|
|
* Helper function to create an encrypted attachment name |
467
|
|
|
* |
468
|
|
|
* @param string $filename |
469
|
|
|
* @return string |
470
|
|
|
*/ |
471
|
|
|
function createAttachmentFilehash($filename) |
472
|
|
|
{ |
473
|
|
|
return sha1(md5($filename . time()) . mt_rand()); |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* Used to copy smileys from a source to destination. |
478
|
|
|
* |
479
|
|
|
* @param string $source |
480
|
|
|
* @param string $dest |
481
|
|
|
* |
482
|
|
|
* @return type |
483
|
|
|
*/ |
484
|
|
|
function copy_smileys($source, $dest) |
485
|
|
|
{ |
486
|
|
|
copy_dir($source, $dest); |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
/** |
490
|
|
|
* Return the attachment extension and mime type |
491
|
|
|
* |
492
|
|
|
* @param string $filename |
493
|
|
|
* |
494
|
|
|
* @return array |
495
|
|
|
*/ |
496
|
|
|
function attachment_type($filename) |
497
|
|
|
{ |
498
|
|
|
// Is this an image (basic ext sniff) |
499
|
|
|
$path_parts = pathinfo($filename); |
500
|
|
|
$ext = $path_parts['extension']; |
501
|
|
|
$basename = $path_parts['filename']; |
502
|
|
|
|
503
|
|
|
if (!in_array(strtolower($ext), array('jpg', 'jpeg', 'gif', 'png'))) |
504
|
|
|
{ |
505
|
|
|
$ext = ''; |
506
|
|
|
$mime_type = ''; |
507
|
|
|
} |
508
|
|
|
else |
509
|
|
|
{ |
510
|
|
|
if (strtolower($ext) === 'jpg') |
511
|
|
|
{ |
512
|
|
|
$mime_type = 'image/jpeg'; |
513
|
|
|
} |
514
|
|
|
else |
515
|
|
|
{ |
516
|
|
|
$mime_type = 'image/' . strtolower($ext); |
517
|
|
|
} |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
return array($ext, $basename, $mime_type); |
521
|
|
|
} |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.