Shortcodes Ultimate - Version 3.0.0

Version Description

Upgrade normally via your Wordpress admin -> Plugins panel.

Download this release

Release Info

Developer gn_themes
Plugin Icon 128x128 Shortcodes Ultimate
Version 3.0.0
Comparing to
See all releases

Code changes from version 2.7.0 to 3.0.0

css/generator.css ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #su-generator-wrap {
2
+ display: none;
3
+ }
4
+
5
+ #su-generator {
6
+ padding: 20px 10px;
7
+ }
8
+
9
+ #su-generator-settings {
10
+ padding: 20px;
11
+ border: 1px dashed #ccc;
12
+ }
13
+
14
+ #su-generator-select {
15
+ width: 300px;
16
+ padding: 5px;
17
+ }
18
+
19
+ #su-generator-settings label {
20
+ float: left;
21
+ display: block;
22
+ width: 200px;
23
+ padding: 5px;
24
+ border-bottom: 1px dotted #ccc;
25
+ }
26
+
27
+ #su-generator-settings input[type="text"] {
28
+ width: 300px;
29
+ padding: 5px 8px;
30
+ }
31
+ #su-generator-settings select {
32
+ width: 300px;
33
+ padding: 5px 8px;
34
+ }
35
+
36
+ .su-loading-animation {
37
+ min-height: 100px;
38
+ background: 50% 50% url(../images/admin/loading.gif) no-repeat;
39
+ }
40
+ .su-loading-animation * {
41
+ display: none;
42
+ }
images/admin/loading.gif ADDED
Binary file
images/admin/media-icon.png ADDED
Binary file
js/generator.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($) {
2
+
3
+ // Select shortcode
4
+ $('#su-generator-select').live( "change", function() {
5
+ var queried_shortcode = $('#su-generator-select').find(':selected').val();
6
+ $('#su-generator-settings').addClass('su-loading-animation');
7
+ $('#su-generator-settings').load($('#su-generator-url').val() + '/lib/generator.php?shortcode=' + queried_shortcode, function() {
8
+ $('#su-generator-settings').removeClass('su-loading-animation');
9
+ });
10
+ });
11
+
12
+ // Insert shortcode
13
+ $('#su-generator-insert').live('click', function() {
14
+ var queried_shortcode = $('#su-generator-select').find(':selected').val();
15
+ $('#su-generator-result').val('[' + queried_shortcode);
16
+ $('#su-generator-settings .su-generator-attr').each(function() {
17
+ if ( $(this).val() !== '' ) {
18
+ $('#su-generator-result').val( $('#su-generator-result').val() + ' ' + $(this).attr('name') + '="' + $(this).val() + '"' );
19
+ }
20
+ });
21
+ $('#su-generator-result').val($('#su-generator-result').val() + ']' + $('#su-generator-content').val() + '[/' + queried_shortcode + ']');
22
+ window.send_to_editor(jQuery('#su-generator-result').val());
23
+ });
24
+ });
languages/shortcodes-ultimate-ru_RU.mo CHANGED
Binary file
languages/shortcodes-ultimate-ru_RU.po CHANGED
@@ -2,8 +2,8 @@ msgid ""
2
  msgstr ""
3
  "Project-Id-Version: gn_themes\n"
4
  "Report-Msgid-Bugs-To: \n"
5
- "POT-Creation-Date: 2011-08-03 01:33+0300\n"
6
- "PO-Revision-Date: 2011-08-03 01:34+0300\n"
7
  "Last-Translator: Vladimir Anokhin <ano.vladimir@gmail.com>\n"
8
  "Language-Team: \n"
9
  "MIME-Version: 1.0\n"
@@ -14,34 +14,42 @@ msgstr ""
14
  "X-Poedit-SourceCharset: utf-8\n"
15
  "X-Poedit-SearchPath-0: .\n"
16
 
17
- #: shortcodes-ultimate.php:163
18
  #: lib/admin.php:26
19
  msgid "Shortcodes Ultimate"
20
  msgstr "Шорткоды"
21
 
22
- #: shortcodes-ultimate.php:163
23
  msgid "Vladimir Anokhin"
24
  msgstr "Владимир Анохин"
25
 
26
- #: shortcodes-ultimate.php:163
27
  msgid "Provides support for many easy to use shortcodes"
28
  msgstr "Предоставляет поддержку множества полезных шорткодов"
29
 
30
- #: shortcodes-ultimate.php:249
31
  #: lib/admin.php:35
32
  msgid "Settings"
33
  msgstr "Настройки"
34
 
35
- #: shortcodes-ultimate.php:262
36
  #: lib/admin.php:62
37
  msgid "Settings saved"
38
  msgstr "Настройки сохранены"
39
 
40
- #: shortcodes-ultimate.php:267
41
  #: lib/admin.php:123
42
  msgid "Custom CSS saved"
43
  msgstr "Произвольные стили сохранены"
44
 
 
 
 
 
 
 
 
 
45
  #: lib/admin.php:7
46
  #: lib/admin.php:37
47
  msgid "Shortcodes"
@@ -57,6 +65,7 @@ msgstr "Произвольные стили"
57
 
58
  #: lib/admin.php:38
59
  #: lib/admin.php:175
 
60
  msgid "Demo"
61
  msgstr "Демо"
62
 
@@ -195,378 +204,444 @@ msgid "Usage"
195
  msgstr "Пример использования"
196
 
197
  #: lib/available.php:14
 
 
 
 
198
  msgid "Styled heading"
199
  msgstr "Стильный заголовок"
200
 
201
- #: lib/available.php:28
202
  msgid "Frame align"
203
  msgstr "Выравнивание рамки"
204
 
205
- #: lib/available.php:32
 
 
 
 
206
  msgid "Styled image frame"
207
  msgstr "Стиьная рамка изображения"
208
 
209
- #: lib/available.php:46
210
  msgid "Tabs style"
211
  msgstr "Стиль вкладок"
212
 
213
- #: lib/available.php:50
214
  msgid "Tabs container"
215
  msgstr "Контейнер вкладок"
216
 
217
- #: lib/available.php:59
218
  msgid "Title"
219
  msgstr "Заголовок"
220
 
221
- #: lib/available.php:60
222
  msgid "Tab title"
223
  msgstr "Заголовок вкладки"
224
 
225
- #: lib/available.php:64
 
 
 
 
226
  msgid "Single tab"
227
  msgstr "Одиночная вкладка"
228
 
229
- #: lib/available.php:73
230
- #: lib/available.php:74
231
  #: lib/shortcodes.php:82
232
  msgid "Spoiler title"
233
  msgstr "Скрытый текст"
234
 
235
- #: lib/available.php:78
 
 
 
 
236
  msgid "Hidden text"
237
  msgstr "Скрытый текст"
238
 
239
- #: lib/available.php:91
240
  msgid "Show TOP link"
241
  msgstr "Показать ссылку ВВЕРХ"
242
 
243
- #: lib/available.php:95
244
  msgid "Content divider with optional TOP link"
245
  msgstr "Разделитель текста со ссылкой ВВЕРХ"
246
 
247
- #: lib/available.php:111
248
  msgid "Spacer height in pixels"
249
  msgstr "Высота разделителя в пикселях"
250
 
251
- #: lib/available.php:115
252
  msgid "Empty space with adjustable height"
253
  msgstr "Пробел с настраиваемой высотой"
254
 
255
- #: lib/available.php:129
256
  msgid "Quote style"
257
  msgstr "Стиль цитаты"
258
 
259
- #: lib/available.php:133
 
 
 
 
260
  msgid "Blockquote alternative"
261
  msgstr "Альтернатива цитаты"
262
 
263
- #: lib/available.php:146
264
  msgid "Pullquote alignment"
265
  msgstr "Выравнивание цитаты"
266
 
267
- #: lib/available.php:150
 
268
  msgid "Pullquote"
269
  msgstr "Цитата с обтеканием"
270
 
271
- #: lib/available.php:160
272
  msgid "Background color"
273
  msgstr "Цвет фона"
274
 
275
- #: lib/available.php:165
276
  msgid "Text color"
277
  msgstr "Цвет текста"
278
 
279
- #: lib/available.php:169
 
280
  msgid "Highlighted text"
281
  msgstr "Подсвеченный текст"
282
 
283
- #: lib/available.php:192
284
  msgid "Option name"
285
  msgstr "Имя опции"
286
 
287
- #: lib/available.php:196
288
  msgid "Blog info"
289
  msgstr "Инфо блога"
290
 
291
- #: lib/available.php:206
292
- #: lib/available.php:696
293
- #: lib/available.php:768
294
  msgid "Post/page ID"
295
  msgstr "ID записи/страницы"
296
 
297
- #: lib/available.php:214
298
  msgid "Link target"
299
  msgstr "Цель ссылки"
300
 
301
- #: lib/available.php:218
 
 
 
 
302
  msgid "Permalink to specified post/page"
303
  msgstr "Постоянная ссылка на указанную запись/страницу"
304
 
305
- #: lib/available.php:228
306
  msgid "Button link"
307
  msgstr "Ссылка кнопки"
308
 
309
- #: lib/available.php:233
310
  msgid "Button background color"
311
  msgstr "Цвет фона кнопки"
312
 
313
- #: lib/available.php:251
314
  msgid "Button size"
315
  msgstr "Размер кнопки"
316
 
317
- #: lib/available.php:261
318
  msgid "Button background style"
319
  msgstr "Стиль фона кнопки"
320
 
321
- #: lib/available.php:269
322
  msgid "Dark text color"
323
  msgstr "Темный цвет текста"
324
 
325
- #: lib/available.php:277
326
  msgid "Disable rounded corners"
327
  msgstr "Отключить скругленные уголки"
328
 
329
- #: lib/available.php:282
330
  msgid "Button icon"
331
  msgstr "Иконка кнопки"
332
 
333
- #: lib/available.php:287
334
  msgid "Button class"
335
  msgstr "Класс кнопки"
336
 
337
- #: lib/available.php:295
338
  msgid "Button link target"
339
  msgstr "Цель ссылки кнопки"
340
 
341
- #: lib/available.php:299
 
 
 
 
342
  msgid "Styled button"
343
  msgstr "Стильная кнопка"
344
 
345
- #: lib/available.php:312
346
  msgid "Link color"
347
  msgstr "Цвет ссылки"
348
 
349
- #: lib/available.php:317
350
  msgid "URL"
351
  msgstr "URL"
352
 
353
- #: lib/available.php:321
 
 
 
 
354
  msgid "Fancy link"
355
  msgstr "Стильная ссылка"
356
 
357
- #: lib/available.php:330
358
- #: lib/available.php:331
359
  msgid "Service title"
360
  msgstr "Название услуги"
361
 
362
- #: lib/available.php:336
363
  msgid "Service icon"
364
  msgstr "Иконка услуги"
365
 
366
- #: lib/available.php:345
367
  msgid "Icon size"
368
  msgstr "Размер иконки"
369
 
370
- #: lib/available.php:349
 
 
 
 
371
  msgid "Service box with title"
372
  msgstr "Блок услуга с заголовком"
373
 
374
- #: lib/available.php:363
375
  msgid "Box style"
376
  msgstr "Стиль блока"
377
 
378
- #: lib/available.php:367
 
 
 
 
379
  msgid "Content for logged in members only"
380
  msgstr "Ссодержимое только для залогиненных"
381
 
382
- #: lib/available.php:376
383
- #: lib/available.php:377
384
  msgid "Box title"
385
  msgstr "Заголовок блока"
386
 
387
- #: lib/available.php:382
388
  msgid "Box color"
389
  msgstr "Цвет блока"
390
 
391
- #: lib/available.php:386
 
 
 
 
392
  msgid "Colored box with caption"
393
  msgstr "Цветной блок с заголовком"
394
 
395
- #: lib/available.php:396
396
  msgid "Note color"
397
  msgstr "Цвет блока"
398
 
399
- #: lib/available.php:400
 
 
 
 
400
  msgid "Colored box"
401
  msgstr "Цветной блок"
402
 
403
- #: lib/available.php:408
 
 
 
 
404
  msgid "Private note for post authors"
405
  msgstr "Приватный текст для других авторов"
406
 
407
- #: lib/available.php:434
408
  msgid "List style"
409
  msgstr "Стиль списка"
410
 
411
- #: lib/available.php:438
 
 
 
 
412
  msgid "Styled unordered list"
413
  msgstr "Стильный неупорядоченный список"
414
 
415
- #: lib/available.php:448
416
  msgid "Feed URL"
417
  msgstr "URL ленты"
418
 
419
- #: lib/available.php:459
420
  msgid "Number of item to show"
421
  msgstr "Количество элементов для показа"
422
 
423
- #: lib/available.php:463
424
  msgid "Feed grabber"
425
  msgstr "Граббер новостных лент"
426
 
427
- #: lib/available.php:473
428
  msgid "Custom menu name"
429
  msgstr "Имя произвольного меню"
430
 
431
- #: lib/available.php:477
432
  msgid "Custom menu by name"
433
  msgstr "Произвольное меню"
434
 
435
- #: lib/available.php:491
436
- #: lib/available.php:514
437
  msgid "Depth level"
438
  msgstr "Глубина"
439
 
440
- #: lib/available.php:496
441
  msgid "Parent page ID"
442
  msgstr "ID родительской страницы"
443
 
444
- #: lib/available.php:500
445
- #: lib/available.php:518
446
  msgid "Page childrens"
447
  msgstr "Потомки страницы"
448
 
449
- #: lib/available.php:540
450
  msgid "Column width"
451
  msgstr "Ширина колонки"
452
 
453
- #: lib/available.php:548
454
- msgid "For last columns"
455
- msgstr "Для последних колонок"
456
 
457
- #: lib/available.php:557
458
- msgid "You can define custom styles for each columns set"
459
- msgstr "Вы можете определить особые стили для каждого набора колонок"
460
 
461
- #: lib/available.php:561
 
 
 
 
462
  msgid "Flexible columns"
463
  msgstr "Резновые колонки"
464
 
465
- #: lib/available.php:575
466
  msgid "Table style"
467
  msgstr "Стиль таблицы"
468
 
469
- #: lib/available.php:580
470
  msgid "Create table from CSV"
471
  msgstr "Создание таблицы из CSV файла"
472
 
473
- #: lib/available.php:584
474
  msgid "Styled table from HTML or CSV file"
475
  msgstr "Стильная таблица из HTML или CSV файла"
476
 
477
- #: lib/available.php:594
478
  msgid "Media URL"
479
  msgstr "Ссылка на медиа"
480
 
481
- #: lib/available.php:599
482
- #: lib/available.php:623
483
- #: lib/available.php:642
484
  msgid "Width"
485
  msgstr "Ширина"
486
 
487
- #: lib/available.php:604
488
- #: lib/available.php:628
489
- #: lib/available.php:647
490
  msgid "Height"
491
  msgstr "Высота"
492
 
493
- #: lib/available.php:608
494
  msgid "YouTube video, Vimeo video, .mp4/.flv video, .mp3 file or images"
495
  msgstr "YouTube видео, Vimeo видео, .mp4/.flv видео, .mp3 файл или изображения"
496
 
497
- #: lib/available.php:618
498
  msgid "Document URL"
499
  msgstr "Ссылка на документ"
500
 
501
- #: lib/available.php:632
502
  msgid ".doc, .xls, .pdf viewer by Google"
503
  msgstr ".doc, .xls, .pdf просмотрщик от Google"
504
 
505
- #: lib/available.php:652
506
  msgid "Marker address"
507
  msgstr "Адрес маркера"
508
 
509
- #: lib/available.php:656
510
  msgid "Maps by Google"
511
  msgstr "Карты от Google"
512
 
513
- #: lib/available.php:666
514
  msgid "Slider width"
515
  msgstr "Ширина слайдера"
516
 
517
- #: lib/available.php:671
518
  msgid "Slider height"
519
  msgstr "Высота слайдера"
520
 
521
- #: lib/available.php:681
522
  msgid "Slides links"
523
  msgstr "Ссылки слайдов"
524
 
525
- #: lib/available.php:686
526
- #: lib/available.php:763
527
  msgid "Animation speed (1000 = 1 second)"
528
  msgstr "Скорость анимации (1000 = 1 секунда)"
529
 
530
- #: lib/available.php:691
531
  msgid "Animation delay (1000 = 1 second)"
532
  msgstr "Задержка анимации (1000 = 1 секунда)"
533
 
534
- #: lib/available.php:706
535
  msgid "Animation effect"
536
  msgstr "Эффект анимации"
537
 
538
- #: lib/available.php:710
539
  msgid "Nivo slider by attached to post images"
540
  msgstr "Nivo slider из изображений записи"
541
 
542
- #: lib/available.php:720
543
  msgid "Carousel width"
544
  msgstr "Ширина карусели"
545
 
546
- #: lib/available.php:725
547
  msgid "Carousel height"
548
  msgstr "Высота карусели"
549
 
550
- #: lib/available.php:730
551
  msgid "Carousel background"
552
  msgstr "Фон карусели"
553
 
554
- #: lib/available.php:739
555
  msgid "Number of items to show"
556
  msgstr "Количество элементов для показа"
557
 
558
- #: lib/available.php:748
559
  msgid "Space between items in pixels"
560
  msgstr "Расстояние между элементами в пикселях"
561
 
562
- #: lib/available.php:758
563
  msgid "Items links"
564
  msgstr "Ссылки элементов"
565
 
566
- #: lib/available.php:772
567
  msgid "jCarousel by attached to post images"
568
  msgstr "jCarousel из изображений записи"
569
 
 
 
 
 
570
  #: lib/shortcodes.php:101
571
  msgid "Top"
572
  msgstr "Вверх"
@@ -600,8 +675,8 @@ msgstr "Это содержимое только для участников."
600
  msgid "Please login"
601
  msgstr "Пожалуйста войдите"
602
 
603
- #~ msgid "Content"
604
- #~ msgstr "Содержимое"
605
 
606
  #~ msgid "Tab name"
607
  #~ msgstr "Имя вкладки"
@@ -615,9 +690,6 @@ msgstr "Пожалуйста войдите"
615
  #~ msgid "image url"
616
  #~ msgstr "ссылка на изображение"
617
 
618
- #~ msgid "Service description"
619
- #~ msgstr "Описание услуги"
620
-
621
  #~ msgid "Content for registered users"
622
  #~ msgstr "Содержимое для залогиненых посетителей"
623
 
2
  msgstr ""
3
  "Project-Id-Version: gn_themes\n"
4
  "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2011-08-09 09:09+0300\n"
6
+ "PO-Revision-Date: 2011-08-09 09:12+0300\n"
7
  "Last-Translator: Vladimir Anokhin <ano.vladimir@gmail.com>\n"
8
  "Language-Team: \n"
9
  "MIME-Version: 1.0\n"
14
  "X-Poedit-SourceCharset: utf-8\n"
15
  "X-Poedit-SearchPath-0: .\n"
16
 
17
+ #: shortcodes-ultimate.php:179
18
  #: lib/admin.php:26
19
  msgid "Shortcodes Ultimate"
20
  msgstr "Шорткоды"
21
 
22
+ #: shortcodes-ultimate.php:179
23
  msgid "Vladimir Anokhin"
24
  msgstr "Владимир Анохин"
25
 
26
+ #: shortcodes-ultimate.php:179
27
  msgid "Provides support for many easy to use shortcodes"
28
  msgstr "Предоставляет поддержку множества полезных шорткодов"
29
 
30
+ #: shortcodes-ultimate.php:265
31
  #: lib/admin.php:35
32
  msgid "Settings"
33
  msgstr "Настройки"
34
 
35
+ #: shortcodes-ultimate.php:278
36
  #: lib/admin.php:62
37
  msgid "Settings saved"
38
  msgstr "Настройки сохранены"
39
 
40
+ #: shortcodes-ultimate.php:283
41
  #: lib/admin.php:123
42
  msgid "Custom CSS saved"
43
  msgstr "Произвольные стили сохранены"
44
 
45
+ #: shortcodes-ultimate.php:291
46
+ msgid "Insert shortcode"
47
+ msgstr "Вставка шорткода"
48
+
49
+ #: shortcodes-ultimate.php:305
50
+ msgid "Select shortcode"
51
+ msgstr "Выберите шорткод"
52
+
53
  #: lib/admin.php:7
54
  #: lib/admin.php:37
55
  msgid "Shortcodes"
65
 
66
  #: lib/admin.php:38
67
  #: lib/admin.php:175
68
+ #: lib/generator.php:41
69
  msgid "Demo"
70
  msgstr "Демо"
71
 
204
  msgstr "Пример использования"
205
 
206
  #: lib/available.php:14
207
+ msgid "Heading"
208
+ msgstr "Заголовок"
209
+
210
+ #: lib/available.php:15
211
  msgid "Styled heading"
212
  msgstr "Стильный заголовок"
213
 
214
+ #: lib/available.php:29
215
  msgid "Frame align"
216
  msgstr "Выравнивание рамки"
217
 
218
+ #: lib/available.php:33
219
+ msgid "Image tag"
220
+ msgstr "Тег изображения"
221
+
222
+ #: lib/available.php:34
223
  msgid "Styled image frame"
224
  msgstr "Стиьная рамка изображения"
225
 
226
+ #: lib/available.php:48
227
  msgid "Tabs style"
228
  msgstr "Стиль вкладок"
229
 
230
+ #: lib/available.php:52
231
  msgid "Tabs container"
232
  msgstr "Контейнер вкладок"
233
 
234
+ #: lib/available.php:61
235
  msgid "Title"
236
  msgstr "Заголовок"
237
 
238
+ #: lib/available.php:62
239
  msgid "Tab title"
240
  msgstr "Заголовок вкладки"
241
 
242
+ #: lib/available.php:66
243
+ msgid "Tab content"
244
+ msgstr "Содержимое вкладки"
245
+
246
+ #: lib/available.php:67
247
  msgid "Single tab"
248
  msgstr "Одиночная вкладка"
249
 
250
+ #: lib/available.php:76
251
+ #: lib/available.php:77
252
  #: lib/shortcodes.php:82
253
  msgid "Spoiler title"
254
  msgstr "Скрытый текст"
255
 
256
+ #: lib/available.php:81
257
+ msgid "Hidden content"
258
+ msgstr "Скрытое содержимое"
259
+
260
+ #: lib/available.php:82
261
  msgid "Hidden text"
262
  msgstr "Скрытый текст"
263
 
264
+ #: lib/available.php:95
265
  msgid "Show TOP link"
266
  msgstr "Показать ссылку ВВЕРХ"
267
 
268
+ #: lib/available.php:99
269
  msgid "Content divider with optional TOP link"
270
  msgstr "Разделитель текста со ссылкой ВВЕРХ"
271
 
272
+ #: lib/available.php:115
273
  msgid "Spacer height in pixels"
274
  msgstr "Высота разделителя в пикселях"
275
 
276
+ #: lib/available.php:119
277
  msgid "Empty space with adjustable height"
278
  msgstr "Пробел с настраиваемой высотой"
279
 
280
+ #: lib/available.php:133
281
  msgid "Quote style"
282
  msgstr "Стиль цитаты"
283
 
284
+ #: lib/available.php:137
285
+ msgid "Quote"
286
+ msgstr "Цитата"
287
+
288
+ #: lib/available.php:138
289
  msgid "Blockquote alternative"
290
  msgstr "Альтернатива цитаты"
291
 
292
+ #: lib/available.php:151
293
  msgid "Pullquote alignment"
294
  msgstr "Выравнивание цитаты"
295
 
296
+ #: lib/available.php:155
297
+ #: lib/available.php:156
298
  msgid "Pullquote"
299
  msgstr "Цитата с обтеканием"
300
 
301
+ #: lib/available.php:166
302
  msgid "Background color"
303
  msgstr "Цвет фона"
304
 
305
+ #: lib/available.php:171
306
  msgid "Text color"
307
  msgstr "Цвет текста"
308
 
309
+ #: lib/available.php:175
310
+ #: lib/available.php:176
311
  msgid "Highlighted text"
312
  msgstr "Подсвеченный текст"
313
 
314
+ #: lib/available.php:199
315
  msgid "Option name"
316
  msgstr "Имя опции"
317
 
318
+ #: lib/available.php:203
319
  msgid "Blog info"
320
  msgstr "Инфо блога"
321
 
322
+ #: lib/available.php:213
323
+ #: lib/available.php:714
324
+ #: lib/available.php:786
325
  msgid "Post/page ID"
326
  msgstr "ID записи/страницы"
327
 
328
+ #: lib/available.php:221
329
  msgid "Link target"
330
  msgstr "Цель ссылки"
331
 
332
+ #: lib/available.php:225
333
+ msgid "Permalink text"
334
+ msgstr "Текст постоянной ссылки"
335
+
336
+ #: lib/available.php:226
337
  msgid "Permalink to specified post/page"
338
  msgstr "Постоянная ссылка на указанную запись/страницу"
339
 
340
+ #: lib/available.php:236
341
  msgid "Button link"
342
  msgstr "Ссылка кнопки"
343
 
344
+ #: lib/available.php:241
345
  msgid "Button background color"
346
  msgstr "Цвет фона кнопки"
347
 
348
+ #: lib/available.php:259
349
  msgid "Button size"
350
  msgstr "Размер кнопки"
351
 
352
+ #: lib/available.php:269
353
  msgid "Button background style"
354
  msgstr "Стиль фона кнопки"
355
 
356
+ #: lib/available.php:277
357
  msgid "Dark text color"
358
  msgstr "Темный цвет текста"
359
 
360
+ #: lib/available.php:285
361
  msgid "Disable rounded corners"
362
  msgstr "Отключить скругленные уголки"
363
 
364
+ #: lib/available.php:290
365
  msgid "Button icon"
366
  msgstr "Иконка кнопки"
367
 
368
+ #: lib/available.php:295
369
  msgid "Button class"
370
  msgstr "Класс кнопки"
371
 
372
+ #: lib/available.php:303
373
  msgid "Button link target"
374
  msgstr "Цель ссылки кнопки"
375
 
376
+ #: lib/available.php:307
377
+ msgid "Button text"
378
+ msgstr "Текст кнопки"
379
+
380
+ #: lib/available.php:308
381
  msgid "Styled button"
382
  msgstr "Стильная кнопка"
383
 
384
+ #: lib/available.php:321
385
  msgid "Link color"
386
  msgstr "Цвет ссылки"
387
 
388
+ #: lib/available.php:326
389
  msgid "URL"
390
  msgstr "URL"
391
 
392
+ #: lib/available.php:330
393
+ msgid "Link text"
394
+ msgstr "Текст ссылки"
395
+
396
+ #: lib/available.php:331
397
  msgid "Fancy link"
398
  msgstr "Стильная ссылка"
399
 
400
+ #: lib/available.php:340
401
+ #: lib/available.php:341
402
  msgid "Service title"
403
  msgstr "Название услуги"
404
 
405
+ #: lib/available.php:346
406
  msgid "Service icon"
407
  msgstr "Иконка услуги"
408
 
409
+ #: lib/available.php:355
410
  msgid "Icon size"
411
  msgstr "Размер иконки"
412
 
413
+ #: lib/available.php:359
414
+ msgid "Service description"
415
+ msgstr "Описание услуги"
416
+
417
+ #: lib/available.php:360
418
  msgid "Service box with title"
419
  msgstr "Блок услуга с заголовком"
420
 
421
+ #: lib/available.php:374
422
  msgid "Box style"
423
  msgstr "Стиль блока"
424
 
425
+ #: lib/available.php:378
426
+ msgid "Contnt for logged members"
427
+ msgstr "Содержимое для залогиненных пользователей"
428
+
429
+ #: lib/available.php:379
430
  msgid "Content for logged in members only"
431
  msgstr "Ссодержимое только для залогиненных"
432
 
433
+ #: lib/available.php:388
434
+ #: lib/available.php:389
435
  msgid "Box title"
436
  msgstr "Заголовок блока"
437
 
438
+ #: lib/available.php:394
439
  msgid "Box color"
440
  msgstr "Цвет блока"
441
 
442
+ #: lib/available.php:398
443
+ msgid "Box content"
444
+ msgstr "Содержимое блока"
445
+
446
+ #: lib/available.php:399
447
  msgid "Colored box with caption"
448
  msgstr "Цветной блок с заголовком"
449
 
450
+ #: lib/available.php:409
451
  msgid "Note color"
452
  msgstr "Цвет блока"
453
 
454
+ #: lib/available.php:413
455
+ msgid "Note text"
456
+ msgstr "Текст заметки"
457
+
458
+ #: lib/available.php:414
459
  msgid "Colored box"
460
  msgstr "Цветной блок"
461
 
462
+ #: lib/available.php:422
463
+ msgid "Private note text"
464
+ msgstr "Текст приватной заметки"
465
+
466
+ #: lib/available.php:423
467
  msgid "Private note for post authors"
468
  msgstr "Приватный текст для других авторов"
469
 
470
+ #: lib/available.php:449
471
  msgid "List style"
472
  msgstr "Стиль списка"
473
 
474
+ #: lib/available.php:453
475
+ msgid "List item "
476
+ msgstr "Элемент списка"
477
+
478
+ #: lib/available.php:454
479
  msgid "Styled unordered list"
480
  msgstr "Стильный неупорядоченный список"
481
 
482
+ #: lib/available.php:464
483
  msgid "Feed URL"
484
  msgstr "URL ленты"
485
 
486
+ #: lib/available.php:475
487
  msgid "Number of item to show"
488
  msgstr "Количество элементов для показа"
489
 
490
+ #: lib/available.php:479
491
  msgid "Feed grabber"
492
  msgstr "Граббер новостных лент"
493
 
494
+ #: lib/available.php:489
495
  msgid "Custom menu name"
496
  msgstr "Имя произвольного меню"
497
 
498
+ #: lib/available.php:493
499
  msgid "Custom menu by name"
500
  msgstr "Произвольное меню"
501
 
502
+ #: lib/available.php:507
503
+ #: lib/available.php:530
504
  msgid "Depth level"
505
  msgstr "Глубина"
506
 
507
+ #: lib/available.php:512
508
  msgid "Parent page ID"
509
  msgstr "ID родительской страницы"
510
 
511
+ #: lib/available.php:516
512
+ #: lib/available.php:534
513
  msgid "Page childrens"
514
  msgstr "Потомки страницы"
515
 
516
+ #: lib/available.php:556
517
  msgid "Column width"
518
  msgstr "Ширина колонки"
519
 
520
+ #: lib/available.php:564
521
+ msgid "Last column"
522
+ msgstr "Последняя колонка"
523
 
524
+ #: lib/available.php:573
525
+ msgid "Column style"
526
+ msgstr "Стиль колонки"
527
 
528
+ #: lib/available.php:577
529
+ msgid "Column content"
530
+ msgstr "Содержимое колонки"
531
+
532
+ #: lib/available.php:578
533
  msgid "Flexible columns"
534
  msgstr "Резновые колонки"
535
 
536
+ #: lib/available.php:592
537
  msgid "Table style"
538
  msgstr "Стиль таблицы"
539
 
540
+ #: lib/available.php:597
541
  msgid "Create table from CSV"
542
  msgstr "Создание таблицы из CSV файла"
543
 
544
+ #: lib/available.php:602
545
  msgid "Styled table from HTML or CSV file"
546
  msgstr "Стильная таблица из HTML или CSV файла"
547
 
548
+ #: lib/available.php:612
549
  msgid "Media URL"
550
  msgstr "Ссылка на медиа"
551
 
552
+ #: lib/available.php:617
553
+ #: lib/available.php:641
554
+ #: lib/available.php:660
555
  msgid "Width"
556
  msgstr "Ширина"
557
 
558
+ #: lib/available.php:622
559
+ #: lib/available.php:646
560
+ #: lib/available.php:665
561
  msgid "Height"
562
  msgstr "Высота"
563
 
564
+ #: lib/available.php:626
565
  msgid "YouTube video, Vimeo video, .mp4/.flv video, .mp3 file or images"
566
  msgstr "YouTube видео, Vimeo видео, .mp4/.flv видео, .mp3 файл или изображения"
567
 
568
+ #: lib/available.php:636
569
  msgid "Document URL"
570
  msgstr "Ссылка на документ"
571
 
572
+ #: lib/available.php:650
573
  msgid ".doc, .xls, .pdf viewer by Google"
574
  msgstr ".doc, .xls, .pdf просмотрщик от Google"
575
 
576
+ #: lib/available.php:670
577
  msgid "Marker address"
578
  msgstr "Адрес маркера"
579
 
580
+ #: lib/available.php:674
581
  msgid "Maps by Google"
582
  msgstr "Карты от Google"
583
 
584
+ #: lib/available.php:684
585
  msgid "Slider width"
586
  msgstr "Ширина слайдера"
587
 
588
+ #: lib/available.php:689
589
  msgid "Slider height"
590
  msgstr "Высота слайдера"
591
 
592
+ #: lib/available.php:699
593
  msgid "Slides links"
594
  msgstr "Ссылки слайдов"
595
 
596
+ #: lib/available.php:704
597
+ #: lib/available.php:781
598
  msgid "Animation speed (1000 = 1 second)"
599
  msgstr "Скорость анимации (1000 = 1 секунда)"
600
 
601
+ #: lib/available.php:709
602
  msgid "Animation delay (1000 = 1 second)"
603
  msgstr "Задержка анимации (1000 = 1 секунда)"
604
 
605
+ #: lib/available.php:724
606
  msgid "Animation effect"
607
  msgstr "Эффект анимации"
608
 
609
+ #: lib/available.php:728
610
  msgid "Nivo slider by attached to post images"
611
  msgstr "Nivo slider из изображений записи"
612
 
613
+ #: lib/available.php:738
614
  msgid "Carousel width"
615
  msgstr "Ширина карусели"
616
 
617
+ #: lib/available.php:743
618
  msgid "Carousel height"
619
  msgstr "Высота карусели"
620
 
621
+ #: lib/available.php:748
622
  msgid "Carousel background"
623
  msgstr "Фон карусели"
624
 
625
+ #: lib/available.php:757
626
  msgid "Number of items to show"
627
  msgstr "Количество элементов для показа"
628
 
629
+ #: lib/available.php:766
630
  msgid "Space between items in pixels"
631
  msgstr "Расстояние между элементами в пикселях"
632
 
633
+ #: lib/available.php:776
634
  msgid "Items links"
635
  msgstr "Ссылки элементов"
636
 
637
+ #: lib/available.php:790
638
  msgid "jCarousel by attached to post images"
639
  msgstr "jCarousel из изображений записи"
640
 
641
+ #: lib/generator.php:40
642
+ msgid "Insert"
643
+ msgstr "Вставить"
644
+
645
  #: lib/shortcodes.php:101
646
  msgid "Top"
647
  msgstr "Вверх"
675
  msgid "Please login"
676
  msgstr "Пожалуйста войдите"
677
 
678
+ #~ msgid "You can define custom styles for each columns set"
679
+ #~ msgstr "Вы можете определить особые стили для каждого набора колонок"
680
 
681
  #~ msgid "Tab name"
682
  #~ msgstr "Имя вкладки"
690
  #~ msgid "image url"
691
  #~ msgstr "ссылка на изображение"
692
 
 
 
 
693
  #~ msgid "Content for registered users"
694
  #~ msgstr "Содержимое для залогиненых посетителей"
695
 
lib/available.php CHANGED
@@ -11,6 +11,7 @@
11
  'type' => 'wrap',
12
  'atts' => array( ),
13
  'usage' => '[heading] Content [/heading]',
 
14
  'desc' => __( 'Styled heading', 'shortcodes-ultimate' )
15
  ),
16
  # frame
@@ -29,6 +30,7 @@
29
  )
30
  ),
31
  'usage' => '[frame align="center"] <img src="image.jpg" alt="" /> [/frame]',
 
32
  'desc' => __( 'Styled image frame', 'shortcodes-ultimate' )
33
  ),
34
  # tabs
@@ -61,6 +63,7 @@
61
  )
62
  ),
63
  'usage' => '[tabs style="1"] [tab title="Tab name"] Tab content [/tab] [/tabs]',
 
64
  'desc' => __( 'Single tab', 'shortcodes-ultimate' )
65
  ),
66
  # spoiler
@@ -75,6 +78,7 @@
75
  )
76
  ),
77
  'usage' => '[spoiler title="Spoiler title"] Hidden text [/spoiler]',
 
78
  'desc' => __( 'Hidden text', 'shortcodes-ultimate' )
79
  ),
80
  # divider
@@ -107,7 +111,7 @@
107
  '20',
108
  '40'
109
  ),
110
- 'default' => '0',
111
  'desc' => __( 'Spacer height in pixels', 'shortcodes-ultimate' )
112
  )
113
  ),
@@ -130,6 +134,7 @@
130
  )
131
  ),
132
  'usage' => '[quote style="1"] Content [/quote]',
 
133
  'desc' => __( 'Blockquote alternative', 'shortcodes-ultimate' )
134
  ),
135
  # pullquote
@@ -147,6 +152,7 @@
147
  )
148
  ),
149
  'usage' => '[pullquote align="left"] Content [/pullquote]',
 
150
  'desc' => __( 'Pullquote', 'shortcodes-ultimate' )
151
  ),
152
  # highlight
@@ -166,6 +172,7 @@
166
  )
167
  ),
168
  'usage' => '[highlight bg="#fc0" color="#000"] Content [/highlight]',
 
169
  'desc' => __( 'Highlighted text', 'shortcodes-ultimate' )
170
  ),
171
  # bloginfo
@@ -215,6 +222,7 @@
215
  ),
216
  ),
217
  'usage' => '[permalink p=52]<br/>[permalink p="52" target="blank"] Content [/permalink]',
 
218
  'desc' => __( 'Permalink to specified post/page', 'shortcodes-ultimate' )
219
  ),
220
  # button
@@ -296,6 +304,7 @@
296
  )
297
  ),
298
  'usage' => '[button link="#" color="#b00" size="3" style="3" dark="1" square="1" icon="image.png"] Button text [/button]',
 
299
  'desc' => __( 'Styled button', 'shortcodes-ultimate' )
300
  ),
301
  # fancy_link
@@ -318,6 +327,7 @@
318
  )
319
  ),
320
  'usage' => '[fancy_link color="black" link="http://example.com/"] Read more [/fancy_link]',
 
321
  'desc' => __( 'Fancy link', 'shortcodes-ultimate' )
322
  ),
323
  # service
@@ -346,6 +356,7 @@
346
  )
347
  ),
348
  'usage' => '[service title="Service title" icon="service.png" size="32"] Service description [/service]',
 
349
  'desc' => __( 'Service box with title', 'shortcodes-ultimate' )
350
  ),
351
  # members
@@ -364,6 +375,7 @@
364
  )
365
  ),
366
  'usage' => '[members style="2"] Content for logged users [/members]',
 
367
  'desc' => __( 'Content for logged in members only', 'shortcodes-ultimate' )
368
  ),
369
  # box
@@ -383,6 +395,7 @@
383
  )
384
  ),
385
  'usage' => '[box title="Box title" color="#f00"] Content [/box]',
 
386
  'desc' => __( 'Colored box with caption', 'shortcodes-ultimate' )
387
  ),
388
  # note
@@ -397,6 +410,7 @@
397
  )
398
  ),
399
  'usage' => '[note color="#FFCC00"] Content [/note]',
 
400
  'desc' => __( 'Colored box', 'shortcodes-ultimate' )
401
  ),
402
  # private
@@ -405,6 +419,7 @@
405
  'type' => 'wrap',
406
  'atts' => array( ),
407
  'usage' => '[private] Private content [/private]',
 
408
  'desc' => __( 'Private note for post authors', 'shortcodes-ultimate' )
409
  ),
410
  # list
@@ -435,6 +450,7 @@
435
  )
436
  ),
437
  'usage' => '[list style="check"] <ul> <li> List item </li> </ul> [/list]',
 
438
  'desc' => __( 'Styled unordered list', 'shortcodes-ultimate' )
439
  ),
440
  # feed
@@ -545,7 +561,7 @@
545
  '1'
546
  ),
547
  'default' => '0',
548
- 'desc' => __( 'For last columns', 'shortcodes-ultimate' )
549
  ),
550
  'style' => array(
551
  'values' => array(
@@ -554,10 +570,11 @@
554
  '2'
555
  ),
556
  'default' => '0',
557
- 'desc' => __( 'You can define custom styles for each columns set', 'shortcodes-ultimate' )
558
  )
559
  ),
560
  'usage' => '[column size="1-2"] Content [/column]<br/>[column size="1-2" last="1"] Content [/column]',
 
561
  'desc' => __( 'Flexible columns', 'shortcodes-ultimate' )
562
  ),
563
  # table
@@ -581,6 +598,7 @@
581
  )
582
  ),
583
  'usage' => '[table style="1"] <table> … <table> [/table]<br/>[table style="1" file="http://example.com/file.csv"] [/table]',
 
584
  'desc' => __( 'Styled table from HTML or CSV file', 'shortcodes-ultimate' )
585
  ),
586
  # media
11
  'type' => 'wrap',
12
  'atts' => array( ),
13
  'usage' => '[heading] Content [/heading]',
14
+ 'content' => __( 'Heading', 'shortcodes-ultimate' ),
15
  'desc' => __( 'Styled heading', 'shortcodes-ultimate' )
16
  ),
17
  # frame
30
  )
31
  ),
32
  'usage' => '[frame align="center"] <img src="image.jpg" alt="" /> [/frame]',
33
+ 'content' => __( 'Image tag', 'shortcodes-ultimate' ),
34
  'desc' => __( 'Styled image frame', 'shortcodes-ultimate' )
35
  ),
36
  # tabs
63
  )
64
  ),
65
  'usage' => '[tabs style="1"] [tab title="Tab name"] Tab content [/tab] [/tabs]',
66
+ 'content' => __( 'Tab content', 'shortcodes-ultimate' ),
67
  'desc' => __( 'Single tab', 'shortcodes-ultimate' )
68
  ),
69
  # spoiler
78
  )
79
  ),
80
  'usage' => '[spoiler title="Spoiler title"] Hidden text [/spoiler]',
81
+ 'content' => __( 'Hidden content', 'shortcodes-ultimate' ),
82
  'desc' => __( 'Hidden text', 'shortcodes-ultimate' )
83
  ),
84
  # divider
111
  '20',
112
  '40'
113
  ),
114
+ 'default' => '20',
115
  'desc' => __( 'Spacer height in pixels', 'shortcodes-ultimate' )
116
  )
117
  ),
134
  )
135
  ),
136
  'usage' => '[quote style="1"] Content [/quote]',
137
+ 'content' => __( 'Quote', 'shortcodes-ultimate' ),
138
  'desc' => __( 'Blockquote alternative', 'shortcodes-ultimate' )
139
  ),
140
  # pullquote
152
  )
153
  ),
154
  'usage' => '[pullquote align="left"] Content [/pullquote]',
155
+ 'content' => __( 'Pullquote', 'shortcodes-ultimate' ),
156
  'desc' => __( 'Pullquote', 'shortcodes-ultimate' )
157
  ),
158
  # highlight
172
  )
173
  ),
174
  'usage' => '[highlight bg="#fc0" color="#000"] Content [/highlight]',
175
+ 'content' => __( 'Highlighted text', 'shortcodes-ultimate' ),
176
  'desc' => __( 'Highlighted text', 'shortcodes-ultimate' )
177
  ),
178
  # bloginfo
222
  ),
223
  ),
224
  'usage' => '[permalink p=52]<br/>[permalink p="52" target="blank"] Content [/permalink]',
225
+ 'content' => __( 'Permalink text', 'shortcodes-ultimate' ),
226
  'desc' => __( 'Permalink to specified post/page', 'shortcodes-ultimate' )
227
  ),
228
  # button
304
  )
305
  ),
306
  'usage' => '[button link="#" color="#b00" size="3" style="3" dark="1" square="1" icon="image.png"] Button text [/button]',
307
+ 'content' => __( 'Button text', 'shortcodes-ultimate' ),
308
  'desc' => __( 'Styled button', 'shortcodes-ultimate' )
309
  ),
310
  # fancy_link
327
  )
328
  ),
329
  'usage' => '[fancy_link color="black" link="http://example.com/"] Read more [/fancy_link]',
330
+ 'content' => __( 'Link text', 'shortcodes-ultimate' ),
331
  'desc' => __( 'Fancy link', 'shortcodes-ultimate' )
332
  ),
333
  # service
356
  )
357
  ),
358
  'usage' => '[service title="Service title" icon="service.png" size="32"] Service description [/service]',
359
+ 'content' => __( 'Service description', 'shortcodes-ultimate' ),
360
  'desc' => __( 'Service box with title', 'shortcodes-ultimate' )
361
  ),
362
  # members
375
  )
376
  ),
377
  'usage' => '[members style="2"] Content for logged users [/members]',
378
+ 'content' => __( 'Contnt for logged members', 'shortcodes-ultimate' ),
379
  'desc' => __( 'Content for logged in members only', 'shortcodes-ultimate' )
380
  ),
381
  # box
395
  )
396
  ),
397
  'usage' => '[box title="Box title" color="#f00"] Content [/box]',
398
+ 'content' => __( 'Box content', 'shortcodes-ultimate' ),
399
  'desc' => __( 'Colored box with caption', 'shortcodes-ultimate' )
400
  ),
401
  # note
410
  )
411
  ),
412
  'usage' => '[note color="#FFCC00"] Content [/note]',
413
+ 'content' => __( 'Note text', 'shortcodes-ultimate' ),
414
  'desc' => __( 'Colored box', 'shortcodes-ultimate' )
415
  ),
416
  # private
419
  'type' => 'wrap',
420
  'atts' => array( ),
421
  'usage' => '[private] Private content [/private]',
422
+ 'content' => __( 'Private note text', 'shortcodes-ultimate' ),
423
  'desc' => __( 'Private note for post authors', 'shortcodes-ultimate' )
424
  ),
425
  # list
450
  )
451
  ),
452
  'usage' => '[list style="check"] <ul> <li> List item </li> </ul> [/list]',
453
+ 'content' => '<ul><li>' . __( 'List item ', 'shortcodes-ultimate' ) . '</li></ul>',
454
  'desc' => __( 'Styled unordered list', 'shortcodes-ultimate' )
455
  ),
456
  # feed
561
  '1'
562
  ),
563
  'default' => '0',
564
+ 'desc' => __( 'Last column', 'shortcodes-ultimate' )
565
  ),
566
  'style' => array(
567
  'values' => array(
570
  '2'
571
  ),
572
  'default' => '0',
573
+ 'desc' => __( 'Column style', 'shortcodes-ultimate' )
574
  )
575
  ),
576
  'usage' => '[column size="1-2"] Content [/column]<br/>[column size="1-2" last="1"] Content [/column]',
577
+ 'content' => __( 'Column content', 'shortcodes-ultimate' ),
578
  'desc' => __( 'Flexible columns', 'shortcodes-ultimate' )
579
  ),
580
  # table
598
  )
599
  ),
600
  'usage' => '[table style="1"] <table> … <table> [/table]<br/>[table style="1" file="http://example.com/file.csv"] [/table]',
601
+ 'content' => '<table><tr><td></td></tr></table>',
602
  'desc' => __( 'Styled table from HTML or CSV file', 'shortcodes-ultimate' )
603
  ),
604
  # media
lib/generator.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Start WordPress
4
+ require( '../../../../wp-load.php' );
5
+
6
+ // Capability check
7
+ if ( !current_user_can( 'edit_posts' ) || !current_user_can( 'edit_pages' ) )
8
+ die( 'Access denied' );
9
+
10
+ // Param check
11
+ if ( empty( $_GET['shortcode'] ) )
12
+ die( 'Shortcode not specified' );
13
+
14
+ $shortcode = su_shortcodes( $_GET['shortcode'] );
15
+
16
+ // Shortcode has atts
17
+ if ( count( $shortcode['atts'] ) && $shortcode['atts'] ) {
18
+ foreach ( $shortcode['atts'] as $attr_name => $attr_info ) {
19
+ $return .= '<p>';
20
+ $return .= '<label for="su-generator-attr-' . $attr_name . '">' . $attr_info['desc'] . '</label>';
21
+
22
+ // Select
23
+ if ( count( $attr_info['values'] ) && $attr_info['values'] ) {
24
+ $return .= '<select name="' . $attr_name . '" id="su-generator-attr-' . $attr_name . '" class="su-generator-attr">';
25
+ foreach ( $attr_info['values'] as $attr_value ) {
26
+ $attr_value_selected = ( $attr_info['default'] == $attr_value ) ? ' selected="selected"' : '';
27
+ $return .= '<option' . $attr_value_selected . '>' . $attr_value . '</option>';
28
+ }
29
+ $return .= '</select>';
30
+ }
31
+
32
+ // Text input
33
+ else {
34
+ $return .= '<input type="text" name="' . $attr_name . '" value="' . $attr_info['default'] . '" id="su-generator-attr-' . $attr_name . '" class="su-generator-attr" />';
35
+ }
36
+ $return .= '</p>';
37
+ }
38
+ }
39
+
40
+ $return .= '<p><a class="button-primary" id="su-generator-insert">' . __( 'Insert', 'shortcodes-ultimate' ) . '</a> ';
41
+ $return .= '<a href="' . su_plugin_url() . '/images/demo/' . $_GET['shortcode'] . '.png" target="_blank" class="button alignright">' . __( 'Demo', 'shortcodes-ultimate' ) . '</a></p>';
42
+
43
+ $return .= '<input type="hidden" name="su-generator-content" id="su-generator-content" value="' . $shortcode['content'] . '" />';
44
+
45
+ $return .= '<input type="hidden" name="su-generator-result" id="su-generator-result" value="" />';
46
+
47
+ echo $return;
48
+ ?>
lib/timthumb.php CHANGED
@@ -1,8 +1,9 @@
1
  <?php
2
  /**
3
- * TimThumb script created by Ben Gillbanks, originally created by Tim McDaniels and Darren Hoyt
 
4
  * http://code.google.com/p/timthumb/
5
- *
6
  * GNU General Public License, version 2
7
  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8
  *
@@ -10,753 +11,1087 @@
10
  * http://www.binarymoon.co.uk/projects/timthumb/
11
  */
12
 
13
- define ('CACHE_SIZE', 250); // number of files to store before clearing cache
14
- define ('CACHE_CLEAR', 5); // maximum number of files to delete on each cache clear
15
- define ('CACHE_USE', TRUE); // use the cache files? (mostly for testing)
16
- define ('VERSION', '1.19'); // version number (to force a cache refresh)
17
- define ('DIRECTORY_CACHE', './cache'); // cache directory
18
- define ('MAX_WIDTH', 1000); // maximum image width
19
- define ('MAX_HEIGHT', 1000); // maximum image height
20
- define ('ALLOW_EXTERNAL', TRUE); // allow external website (override security precaution)
21
-
22
- // external domains that are allowed to be displayed on your website
23
- $allowedSites = array (
24
- 'flickr.com',
25
- 'picasa.com',
26
- 'blogger.com',
27
- 'wordpress.com',
28
- 'img.youtube.com',
29
- 'themes.wprender.ru',
30
- 'democontent.wprender.ru',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  );
32
-
33
- // STOP MODIFYING HERE!
34
- // --------------------
35
-
36
- // sort out image source
37
- $src = get_request ('src', '');
38
- if ($src == '' || strlen ($src) <= 3) {
39
- display_error ('no image specified');
40
- }
41
-
42
- // clean params before use
43
- $src = clean_source ($src);
44
-
45
- // get mime type of src
46
- $mime_type = mime_type ($src);
47
-
48
- // check to see if this image is in the cache already
49
- // if already cached then display the image and die
50
- check_cache ($mime_type);
51
-
52
- // cache doesn't exist and then process everything
53
- // check to see if GD function exist
54
- if (!function_exists ('imagecreatetruecolor')) {
55
- display_error ('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
56
- }
57
-
58
- if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
59
- $imageFilters = array (
60
- 1 => array (IMG_FILTER_NEGATE, 0),
61
- 2 => array (IMG_FILTER_GRAYSCALE, 0),
62
- 3 => array (IMG_FILTER_BRIGHTNESS, 1),
63
- 4 => array (IMG_FILTER_CONTRAST, 1),
64
- 5 => array (IMG_FILTER_COLORIZE, 4),
65
- 6 => array (IMG_FILTER_EDGEDETECT, 0),
66
- 7 => array (IMG_FILTER_EMBOSS, 0),
67
- 8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),
68
- 9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),
69
- 10 => array (IMG_FILTER_MEAN_REMOVAL, 0),
70
- 11 => array (IMG_FILTER_SMOOTH, 0),
71
- );
72
- }
73
-
74
- // get standard input properties
75
- $new_width = (int) abs (get_request ('w', 0));
76
- $new_height = (int) abs (get_request ('h', 0));
77
- $zoom_crop = (int) get_request ('zc', 1);
78
- $quality = (int) abs (get_request ('q', 90));
79
- $align = get_request ('a', 'c');
80
- $filters = get_request ('f', '');
81
- $sharpen = (bool) get_request ('s', 0);
82
-
83
- // set default width and height if neither are set already
84
- if ($new_width == 0 && $new_height == 0) {
85
- $new_width = 100;
86
- $new_height = 100;
87
- }
88
-
89
- // ensure size limits can not be abused
90
- $new_width = min ($new_width, MAX_WIDTH);
91
- $new_height = min ($new_height, MAX_HEIGHT);
92
-
93
- // set memory limit to be able to have enough space to resize larger images
94
- ini_set ('memory_limit', '50M');
95
-
96
- if (file_exists ($src)) {
97
-
98
- // open the existing image
99
- $image = open_image ($mime_type, $src);
100
- if ($image === false) {
101
- display_error ('Unable to open image : ' . $src);
102
- }
103
-
104
- // Get original width and height
105
- $width = imagesx ($image);
106
- $height = imagesy ($image);
107
-
108
- // generate new w/h if not provided
109
- if ($new_width && !$new_height) {
110
-
111
- $new_height = floor ($height * ($new_width / $width));
112
-
113
- } else if ($new_height && !$new_width) {
114
-
115
- $new_width = floor ($width * ($new_height / $height));
116
-
117
- }
118
-
119
- // create a new true color image
120
- $canvas = imagecreatetruecolor ($new_width, $new_height);
121
- imagealphablending ($canvas, false);
122
-
123
- // Create a new transparent color for image
124
- $color = imagecolorallocatealpha ($canvas, 0, 0, 0, 127);
125
-
126
- // Completely fill the background of the new image with allocated color.
127
- imagefill ($canvas, 0, 0, $color);
128
-
129
- // Restore transparency blending
130
- imagesavealpha ($canvas, true);
131
-
132
- if ($zoom_crop) {
133
-
134
- $src_x = $src_y = 0;
135
- $src_w = $width;
136
- $src_h = $height;
137
-
138
- $cmp_x = $width / $new_width;
139
- $cmp_y = $height / $new_height;
140
-
141
- // calculate x or y coordinate and width or height of source
142
- if ($cmp_x > $cmp_y) {
143
-
144
- $src_w = round (($width / $cmp_x * $cmp_y));
145
- $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
146
-
147
- } else if ($cmp_y > $cmp_x) {
148
-
149
- $src_h = round (($height / $cmp_y * $cmp_x));
150
- $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
151
-
152
  }
153
 
154
- // positional cropping!
155
- switch ($align) {
156
- case 't':
157
- case 'tl':
158
- case 'lr':
159
- case 'tr':
160
- case 'rt':
161
- $src_y = 0;
162
- break;
163
-
164
- case 'b':
165
- case 'bl':
166
- case 'lb':
167
- case 'br':
168
- case 'rb':
169
- $src_y = $height - $src_h;
170
- break;
171
 
172
- case 'l':
173
- case 'tl':
174
- case 'lt':
175
- case 'bl':
176
- case 'lb':
177
- $src_x = 0;
178
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
- case 'r':
181
- case 'tr':
182
- case 'rt':
183
- case 'br':
184
- case 'rb':
185
- $src_x = $width - $new_width;
186
- $src_x = $width - $src_w;
187
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
- default:
190
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
192
 
193
- imagecopyresampled ($canvas, $image, 0, 0, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
 
 
194
 
195
- } else {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
- // copy and resize part of an image with resampling
198
- imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
- }
 
 
201
 
202
- if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
203
- // apply filters to image
204
- $filterList = explode ('|', $filters);
205
- foreach ($filterList as $fl) {
206
 
207
- $filterSettings = explode (',', $fl);
208
- if (isset ($imageFilters[$filterSettings[0]])) {
 
 
 
209
 
210
- for ($i = 0; $i < 4; $i ++) {
211
- if (!isset ($filterSettings[$i])) {
212
- $filterSettings[$i] = null;
213
- } else {
214
- $filterSettings[$i] = (int) $filterSettings[$i];
215
- }
216
- }
 
 
 
 
 
217
 
218
- switch ($imageFilters[$filterSettings[0]][1]) {
 
219
 
220
- case 1:
221
 
222
- imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
223
- break;
 
 
 
224
 
225
- case 2:
226
 
227
- imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
228
- break;
 
229
 
230
- case 3:
 
 
231
 
232
- imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
233
- break;
 
234
 
235
- case 4:
 
236
 
237
- imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);
238
- break;
239
 
240
- default:
 
241
 
242
- imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);
243
- break;
244
 
245
- }
246
- }
247
- }
248
- }
249
 
250
- // sharpen image
251
- if ($sharpen && function_exists ('imageconvolution')) {
 
252
 
253
- $sharpenMatrix = array (
254
- array (-1,-1,-1),
255
- array (-1,16,-1),
256
- array (-1,-1,-1),
257
- );
258
 
259
- $divisor = 8;
260
- $offset = 0;
 
261
 
262
- imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);
263
 
264
- }
265
 
266
- // output image to browser based on mime type
267
- show_image ($mime_type, $canvas);
268
 
269
- // remove image from memory
270
- imagedestroy ($canvas);
271
 
272
- // if not in cache then clear some space and generate a new file
273
- clean_cache ();
 
274
 
275
- die ();
 
276
 
277
- } else {
 
278
 
279
- if (strlen ($src)) {
280
- display_error ('image ' . $src . ' not found');
281
- } else {
282
- display_error ('no source specified');
283
- }
284
 
285
- }
286
 
 
 
287
 
288
- /**
289
- *
290
- * @global <type> $quality
291
- * @param <type> $mime_type
292
- * @param <type> $image_resized
293
- */
294
- function show_image ($mime_type, $image_resized) {
295
 
296
- global $quality;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
- // check to see if we can write to the cache directory
299
- $cache_file = get_cache_file ($mime_type);
300
 
301
- if (stristr ($mime_type, 'jpeg')) {
302
- imagejpeg ($image_resized, $cache_file, $quality);
303
- } else {
304
- imagepng ($image_resized, $cache_file, floor ($quality * 0.09));
305
- }
306
 
307
- show_cache_file ($mime_type);
 
308
 
309
- }
310
 
 
 
 
 
311
 
312
- /**
313
- *
314
- * @param <type> $property
315
- * @param <type> $default
316
- * @return <type>
317
- */
318
- function get_request ($property, $default = 0) {
319
 
320
- if (isset ($_GET[$property])) {
 
 
 
 
 
 
321
 
322
- return $_GET[$property];
323
 
324
- } else {
325
 
326
- return $default;
 
327
 
328
- }
329
 
330
- }
 
331
 
 
332
 
333
- /**
334
- *
335
- * @param <type> $mime_type
336
- * @param <type> $src
337
- * @return <type>
338
- */
339
- function open_image ($mime_type, $src) {
340
 
341
- $mime_type = strtolower ($mime_type);
342
 
343
- if (stristr ($mime_type, 'gif')) {
 
344
 
345
- $image = imagecreatefromgif ($src);
346
 
347
- } elseif (stristr ($mime_type, 'jpeg')) {
 
348
 
349
- $image = imagecreatefromjpeg ($src);
 
 
 
350
 
351
- } elseif (stristr ($mime_type, 'png')) {
 
352
 
353
- $image = imagecreatefrompng ($src);
 
 
 
 
354
 
355
- }
 
356
 
357
- return $image;
358
 
359
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
 
361
- /**
362
- * clean out old files from the cache
363
- * you can change the number of files to store and to delete per loop in the defines at the top of the code
364
- *
365
- * @return <type>
366
- */
367
- function clean_cache () {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
 
369
- // add an escape
370
- // Reduces the amount of cache clearing to save some processor speed
371
- if (rand (1, 100) > 10) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  return true;
373
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
 
375
- flush ();
376
-
377
- $files = glob (DIRECTORY_CACHE . '/*', GLOB_BRACE);
378
-
379
- if (count ($files) > CACHE_SIZE) {
380
-
381
- $yesterday = time () - (24 * 60 * 60);
382
-
383
- usort ($files, 'filemtime_compare');
384
- $i = 0;
385
-
386
- foreach ($files as $file) {
387
-
388
- $i ++;
389
-
390
- if ($i >= CACHE_CLEAR) {
391
- return;
392
  }
393
-
394
- if (@filemtime ($file) > $yesterday) {
395
- return;
 
 
 
 
 
 
 
 
 
396
  }
397
-
398
- if (file_exists ($file)) {
399
- unlink ($file);
 
 
 
 
 
 
 
 
400
  }
401
-
402
  }
403
-
404
- }
405
-
406
- }
407
-
408
-
409
- /**
410
- * compare the file time of two files
411
- *
412
- * @param <type> $a
413
- * @param <type> $b
414
- * @return <type>
415
- */
416
- function filemtime_compare ($a, $b) {
417
-
418
- $break = explode ('/', $_SERVER['SCRIPT_FILENAME']);
419
- $filename = $break[count ($break) - 1];
420
- $filepath = str_replace ($filename, '', $_SERVER['SCRIPT_FILENAME']);
421
-
422
- $file_a = realpath ($filepath . $a);
423
- $file_b = realpath ($filepath . $b);
424
-
425
- return filemtime ($file_a) - filemtime ($file_b);
426
-
427
- }
428
-
429
-
430
- /**
431
- * determine the file mime type
432
- *
433
- * @param <type> $file
434
- * @return <type>
435
- */
436
- function mime_type ($file) {
437
-
438
- $file_infos = getimagesize ($file);
439
- $mime_type = $file_infos['mime'];
440
-
441
- // use mime_type to determine mime type
442
- if (!preg_match ("/jpg|jpeg|gif|png/i", $mime_type)) {
443
- display_error ('Invalid src mime type: ' . $mime_type);
444
- }
445
-
446
- return $mime_type;
447
-
448
- }
449
-
450
-
451
- /**
452
- *
453
- * @param <type> $mime_type
454
- */
455
- function check_cache ($mime_type) {
456
-
457
- if (CACHE_USE) {
458
-
459
- if (!show_cache_file ($mime_type)) {
460
- // make sure cache dir exists
461
- if (!file_exists (DIRECTORY_CACHE)) {
462
- // give 777 permissions so that developer can overwrite
463
- // files created by web server user
464
- mkdir (DIRECTORY_CACHE);
465
- chmod (DIRECTORY_CACHE, 0777);
466
  }
467
  }
468
-
469
  }
470
-
471
- }
472
-
473
-
474
- /**
475
- *
476
- * @param <type> $mime_type
477
- * @return <type>
478
- */
479
- function show_cache_file ($mime_type) {
480
-
481
- // use browser cache if available to speed up page load
482
- if (isset ($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
483
- if (strtotime ($_SERVER['HTTP_IF_MODIFIED_SINCE']) < strtotime('now')) {
484
- header ('HTTP/1.1 304 Not Modified');
485
- die ();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
  }
487
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
 
489
- $cache_file = get_cache_file ($mime_type);
490
-
491
- if (file_exists ($cache_file)) {
492
-
493
- // change the modified headers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
  $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';
495
  $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';
496
-
497
  // send content headers then display image
498
- header ('Content-Type: ' . $mime_type);
499
- header ('Accept-Ranges: bytes');
500
  header ('Last-Modified: ' . $gmdate_modified);
501
- header ('Content-Length: ' . filesize ($cache_file));
502
- header ('Cache-Control: max-age=864000, must-revalidate');
503
- header ('Expires: ' . $gmdate_expires);
504
-
505
- if (!@readfile ($cache_file)) {
506
- $content = file_get_contents ($cache_file);
507
- if ($content != FALSE) {
508
- echo $content;
509
- } else {
510
- display_error ('cache file could not be loaded');
511
- }
512
  }
513
-
514
- die ();
515
-
516
- }
517
-
518
- return FALSE;
519
-
520
- }
521
-
522
-
523
- /**
524
- *
525
- * @staticvar string $cache_file
526
- * @param <type> $mime_type
527
- * @return string
528
- */
529
- function get_cache_file ($mime_type) {
530
-
531
- static $cache_file;
532
- global $src;
533
-
534
- $file_type = '.png';
535
-
536
- if (stristr ($mime_type, 'jpeg')) {
537
- $file_type = '.jpg';
538
- }
539
-
540
- if (!$cache_file) {
541
- // filemtime is used to make sure updated files get recached
542
- $cache_file = DIRECTORY_CACHE . '/' . md5 ($_SERVER ['QUERY_STRING'] . VERSION . filemtime ($src)) . $file_type;
543
- }
544
-
545
- return $cache_file;
546
-
547
- }
548
-
549
-
550
- /**
551
- *
552
- * @global array $allowedSites
553
- * @param string $src
554
- * @return string
555
- */
556
- function check_external ($src) {
557
-
558
- global $allowedSites;
559
-
560
- if (stristr ($src, 'http://') !== false) {
561
-
562
- $url_info = parse_url ($src);
563
-
564
- // convert youtube video urls
565
- // need to tidy up the code
566
-
567
- if ($url_info['host'] == 'www.youtube.com' || $url_info['host'] == 'youtube.com') {
568
- parse_str ($url_info['query']);
569
-
570
- if (isset ($v)) {
571
- $src = 'http://img.youtube.com/vi/' . $v . '/0.jpg';
572
- $url_info['host'] = 'img.youtube.com';
573
- }
574
  }
 
 
 
 
 
 
 
 
 
575
 
576
- // check allowed sites (if required)
577
- if (ALLOW_EXTERNAL) {
 
578
 
579
- $isAllowedSite = true;
 
 
 
580
 
 
 
 
 
 
 
 
 
 
 
581
  } else {
582
-
583
- $isAllowedSite = false;
584
- foreach ($allowedSites as $site) {
585
- //$site = '/' . addslashes ($site) . '/';
586
- if (stristr($url_info['host'], $site) !== false) {
587
- $isAllowedSite = true;
588
- }
 
 
 
 
 
589
  }
590
-
 
591
  }
592
-
593
- // if allowed
594
- if ($isAllowedSite) {
595
-
596
- $fileDetails = pathinfo ($src);
597
- $ext = strtolower ($fileDetails['extension']);
598
-
599
- $filename = md5 ($src);
600
- $local_filepath = DIRECTORY_CACHE . '/' . $filename . '.' . $ext;
601
-
602
- if (!file_exists ($local_filepath)) {
603
-
604
- if (function_exists ('curl_init')) {
605
-
606
- $fh = fopen ($local_filepath, 'w');
607
- $ch = curl_init ($src);
608
-
609
- curl_setopt ($ch, CURLOPT_TIMEOUT, 15);
610
- curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; rv:1.7.3) Gecko/20041001 Firefox/0.10.1");
611
- curl_setopt ($ch, CURLOPT_URL, $src);
612
- curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);
613
- curl_setopt ($ch, CURLOPT_HEADER, 0);
614
- curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
615
- curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
616
- curl_setopt ($ch, CURLOPT_FILE, $fh);
617
-
618
- if (curl_exec ($ch) === FALSE) {
619
- if (file_exists ($local_filepath)) {
620
- unlink ($local_filepath);
621
- }
622
- display_error ('error reading file ' . $src . ' from remote host: ' . curl_error($ch));
623
- }
624
-
625
- curl_close ($ch);
626
- fclose ($fh);
627
-
628
- } else {
629
-
630
- if (!$img = file_get_contents($src)) {
631
- display_error ('remote file for ' . $src . ' can not be accessed. It is likely that the file permissions are restricted');
632
- }
633
-
634
- if (file_put_contents ($local_filepath, $img) == FALSE) {
635
- display_error ('error writing temporary file');
636
- }
637
-
638
- }
639
-
640
- if (!file_exists ($local_filepath)) {
641
- display_error ('local file for ' . $src . ' can not be created');
642
- }
643
-
 
 
 
 
 
 
 
 
 
 
 
644
  }
645
-
646
- $src = $local_filepath;
647
-
648
  } else {
649
-
650
- display_error ('remote host "' . $url_info['host'] . '" not allowed');
651
-
 
 
 
 
 
 
 
652
  }
653
 
654
- }
655
-
656
- return $src;
657
-
658
- }
659
-
660
-
661
- /**
662
- * tidy up the image source url
663
- *
664
- * @param <type> $src
665
- * @return string
666
- */
667
- function clean_source ($src) {
668
-
669
- $host = str_replace ('www.', '', $_SERVER['HTTP_HOST']);
670
- $regex = "/^((ht|f)tp(s|):\/\/)(www\.|)" . $host . "/i";
671
-
672
- $src = preg_replace ($regex, '', $src);
673
- $src = strip_tags ($src);
674
- $src = str_replace (' ', '%20', $src);
675
- $src = check_external ($src);
676
-
677
- // remove slash from start of string
678
- if (strpos ($src, '/') === 0) {
679
- $src = substr ($src, -(strlen ($src) - 1));
680
- }
681
-
682
- // don't allow users the ability to use '../'
683
- // in order to gain access to files below document root
684
- $src = preg_replace ("/\.\.+\//", "", $src);
685
-
686
- // get path to image on file system
687
- $src = get_document_root ($src) . '/' . $src;
688
-
689
- return $src;
690
-
691
- }
692
-
693
-
694
- /**
695
- *
696
- * @param <type> $src
697
- * @return string
698
- */
699
- function get_document_root ($src) {
700
-
701
- // check for unix servers
702
- if (file_exists ($_SERVER['DOCUMENT_ROOT'] . '/' . $src)) {
703
- return $_SERVER['DOCUMENT_ROOT'];
704
- }
705
-
706
- // check from script filename (to get all directories to timthumb location)
707
- $parts = array_diff (explode ('/', $_SERVER['SCRIPT_FILENAME']), explode ('/', $_SERVER['DOCUMENT_ROOT']));
708
- $path = $_SERVER['DOCUMENT_ROOT'];
709
- foreach ($parts as $part) {
710
- $path .= '/' . $part;
711
- if (file_exists ($path . '/' . $src)) {
712
- return $path;
713
- }
714
- }
715
-
716
- // the relative paths below are useful if timthumb is moved outside of document root
717
- // specifically if installed in wordpress themes like mimbo pro:
718
- // /wp-content/themes/mimbopro/scripts/timthumb.php
719
- $paths = array (
720
- "./",
721
- "../",
722
- "../../",
723
- "../../../",
724
- "../../../../",
725
- "../../../../../"
726
- );
727
-
728
- foreach ($paths as $path) {
729
- if (file_exists ($path . $src)) {
730
- return $path;
731
- }
732
- }
733
-
734
- // special check for microsoft servers
735
- if (!isset ($_SERVER['DOCUMENT_ROOT'])) {
736
- $path = str_replace ("/", "\\", $_SERVER['ORIG_PATH_INFO']);
737
- $path = str_replace ($path, '', $_SERVER['SCRIPT_FILENAME']);
738
-
739
- if (file_exists ($path . '/' . $src)) {
740
- return $path;
741
- }
742
- }
743
-
744
- display_error ('file not found ' . $src, ENT_QUOTES);
745
-
746
  }
747
-
748
-
749
- /**
750
- * generic error message
751
- *
752
- * @param <type> $errorString
753
- */
754
- function display_error ($errorString = '') {
755
-
756
- header ('HTTP/1.1 400 Bad Request');
757
- echo '<pre>' . htmlentities ($errorString);
758
- echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
759
- echo '<br />TimThumb version : ' . VERSION . '</pre>';
760
- die ();
761
-
762
- }
1
  <?php
2
  /**
3
+ * TimThumb by Ben Gillbanks and Mark Maunder
4
+ * Based on work done by Tim McDaniels and Darren Hoyt
5
  * http://code.google.com/p/timthumb/
6
+ *
7
  * GNU General Public License, version 2
8
  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9
  *
11
  * http://www.binarymoon.co.uk/projects/timthumb/
12
  */
13
 
14
+ //Main config vars
15
+ define ('VERSION', '2.4'); // Version of this script
16
+ define ('DEBUG_ON', false); // Enable debug logging to web server error log (STDERR)
17
+ define ('DEBUG_LEVEL', 1); // Debug level 1 is less noisy and 3 is the most noisy
18
+ define ('MEMORY_LIMIT', '30M'); // Set PHP memory limit
19
+ define ('BLOCK_EXTERNAL_LEECHERS', false); // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
20
+
21
+ //Image fetching and caching
22
+ define ('ALLOW_EXTERNAL', TRUE); // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
23
+ define ('ALLOW_ALL_EXTERNAL_SITES', false); // Less secure.
24
+ define ('FILE_CACHE_ENABLED', TRUE); // Should we store resized/modified images on disk to speed things up?
25
+ define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 86400); // How often the cache is cleaned
26
+ define ('FILE_CACHE_MAX_FILE_AGE', 86400); // How old does a file have to be to be deleted from the cache
27
+ define ('FILE_CACHE_SUFFIX', '.timthumb.txt'); // What to put at the end of all files in the cache directory so we can identify them
28
+ define ('FILE_CACHE_DIRECTORY', './cache'); // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
29
+ define ('MAX_FILE_SIZE', 10485760); // 10 Megs is 10485760. This is the max internal or external file size that we'll process.
30
+ define ('CURL_TIMEOUT', 20); // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
31
+ define ('WAIT_BETWEEN_FETCH_ERRORS', 3600); //Time to wait between errors fetching remote file
32
+ //Browser caching
33
+ define ('BROWSER_CACHE_MAX_AGE', 864000); // Time to cache in the browser
34
+ define ('BROWSER_CACHE_DISABLE', false); // Use for testing if you want to disable all browser caching
35
+
36
+ //Image size
37
+ define ('MAX_WIDTH', 1500); // Maximum image width
38
+ define ('MAX_HEIGHT', 1500); // Maximum image height
39
+
40
+ //Image compression is enabled if either of these point to valid paths
41
+ define ('OPTIPNG_PATH', '/usr/bin/optipng'); //This will run first because it gives better compression than pngcrush.
42
+ define ('PNGCRUSH_PATH', '/usr/bin/pngcrush'); //This will only run if OPTIPNG_PATH is not set or is not valid
43
+
44
+ /*
45
+ -------====Website Screenshots configuration - BETA====-------
46
+
47
+ If you just want image thumbnails and don't want website screenshots, you can safely leave this as is.
48
+
49
+ If you would like to get website screenshots set up, you will need root access to your own server.
50
+
51
+ Enable ALLOW_ALL_EXTERNAL_SITES so you can fetch any external web page. This is more secure now that we're using a non-web folder for cache.
52
+ Enable BLOCK_EXTERNAL_LEECHERS so that your site doesn't generate thumbnails for the whole Internet.
53
+
54
+ Instructions to get website screenshots enabled on Ubuntu Linux:
55
+
56
+ 1. Install Xvfb with the following command: sudo apt-get install subversion libqt4-webkit libqt4-dev g++ xvfb
57
+ 2. Go to a directory where you can download some code
58
+ 3. Check-out the latest version of CutyCapt with the following command: svn co https://cutycapt.svn.sourceforge.net/svnroot/cutycapt
59
+ 4. Compile CutyCapt by doing: cd cutycapt/CutyCapt
60
+ 5. qmake
61
+ 6. make
62
+ 7. cp CutyCapt /usr/local/bin/
63
+ 8. Test it by running: xvfb-run --server-args="-screen 0, 1024x768x24" CutyCapt --url="http://markmaunder.com/" --out=test.png
64
+ 9. If you get a file called test.png with something in it, it probably worked. Now test the script by accessing it as follows:
65
+ 10. http://yoursite.com/path/to/timthumb.php?src=http://markmaunder.com/&webshot=1
66
+
67
+ Notes on performance:
68
+ The first time a webshot loads, it will take a few seconds.
69
+ From then on it uses the regular timthumb caching mechanism with the configurable options above
70
+ and loading will be very fast.
71
+
72
+ --ADVANCED USERS ONLY--
73
+ If you'd like a slight speedup (about 25%) and you know Linux, you can run the following command which will keep Xvfb running in the background.
74
+ nohup Xvfb :100 -ac -nolisten tcp -screen 0, 1024x768x24 > /dev/null 2>&1 &
75
+ Then set WEBSHOT_XVFB_RUNNING = true below. This will save your server having to fire off a new Xvfb server and shut it down every time a new shot is generated.
76
+ You will need to take responsibility for keeping Xvfb running in case it crashes. (It seems pretty stable)
77
+ You will also need to take responsibility for server security if you're running Xvfb as root.
78
+
79
+
80
+ */
81
+ define ('WEBSHOT_ENABLED', false); //Beta feature. Adding webshot=1 to your query string will cause the script to return a browser screenshot rather than try to fetch an image.
82
+ define ('WEBSHOT_CUTYCAPT', '/usr/local/bin/CutyCapt'); //The path to CutyCapt.
83
+ define ('WEBSHOT_XVFB', '/usr/bin/xvfb-run'); //The path to the Xvfb server
84
+ define ('WEBSHOT_SCREEN_X', '1024'); //1024 works ok
85
+ define ('WEBSHOT_SCREEN_Y', '768'); //768 works ok
86
+ define ('WEBSHOT_COLOR_DEPTH', '24'); //I haven't tested anything besides 24
87
+ define ('WEBSHOT_IMAGE_FORMAT', 'png'); //png is about 2.5 times the size of jpg but is a LOT better quality
88
+ define ('WEBSHOT_TIMEOUT', '300'); //Seconds to wait for a webshot
89
+ define ('WEBSHOT_USER_AGENT', "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18"); //I hate to do this, but a non-browser robot user agent might not show what humans see. So we pretend to be Firefox
90
+ define ('WEBSHOT_JAVASCRIPT_ON', true); //Setting to false might give you a slight speedup and block ads. But it could cause other issues.
91
+ define ('WEBSHOT_JAVA_ON', false); //Have only tested this as fase
92
+ define ('WEBSHOT_PLUGINS_ON', true); //Enable flash and other plugins
93
+ define ('WEBSHOT_PROXY', ''); //In case you're behind a proxy server.
94
+ define ('WEBSHOT_XVFB_RUNNING', false); //ADVANCED: Enable this if you've got Xvfb running in the background.
95
+
96
+
97
+ // If ALLOW_EXTERNAL is true and ALLOW_ALL_EXTERNAL_SITES is false, then external images will only be fetched from these domains and their subdomains.
98
+ $ALLOWED_SITES = array (
99
+ 'flickr.com',
100
+ 'picasa.com',
101
+ 'img.youtube.com',
102
+ 'upload.wikimedia.org',
103
+ 'photobucket.com',
104
+ 'imgur.com',
105
+ 'imageshack.us',
106
+ 'tinypic.com'
107
  );
108
+ // -------------------------------------------------------------
109
+ // -------------- STOP EDITING CONFIGURATION HERE --------------
110
+ // -------------------------------------------------------------
111
+
112
+ timthumb::start();
113
+
114
+ class timthumb {
115
+ protected $src = "";
116
+ protected $docRoot = "";
117
+ protected $lastURLError = false;
118
+ protected $localImage = "";
119
+ protected $localImageMTime = 0;
120
+ protected $url = false;
121
+ protected $myHost = "";
122
+ protected $isURL = false;
123
+ protected $cachefile = '';
124
+ protected $errors = array();
125
+ protected $toDeletes = array();
126
+ protected $cacheDirectory = '';
127
+ protected $startTime = 0;
128
+ protected $lastBenchTime = 0;
129
+ protected $isOwnHost = false;
130
+ protected $cropTop = false;
131
+ protected $salt = "";
132
+ protected $fileCacheVersion = 1; //Generally if timthumb.php is modifed (upgraded) then the salt changes and all cache files are recreated. This is a backup mechanism to force regen.
133
+ protected $filePrependSecurityBlock = "<?php die('Execution denied!'); //"; //Designed to have three letter mime type, space, question mark and greater than symbol appended. 6 bytes total.
134
+ protected static $curlDataWritten = 0;
135
+ protected static $curlFH = false;
136
+ public static function start(){
137
+ $tim = new timthumb();
138
+ $tim->handleErrors();
139
+ $tim->securityChecks();
140
+ if($tim->tryBrowserCache()){
141
+ exit(0);
142
+ }
143
+ $tim->handleErrors();
144
+ if(FILE_CACHE_ENABLED && $tim->tryServerCache()){
145
+ exit(0);
146
+ }
147
+ $tim->handleErrors();
148
+ $tim->run();
149
+ $tim->handleErrors();
150
+ exit(0);
151
+ }
152
+ public function __construct(){
153
+ global $ALLOWED_SITES;
154
+ $this->startTime = microtime(true);
155
+ $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']);
156
+ $this->calcDocRoot();
157
+ //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this.
158
+ $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);
159
+ $this->debug(3, "Salt is: " . $this->salt);
160
+ if(FILE_CACHE_DIRECTORY){
161
+ if(! is_dir(FILE_CACHE_DIRECTORY)){
162
+ @mkdir(FILE_CACHE_DIRECTORY);
163
+ if(! is_dir(FILE_CACHE_DIRECTORY)){
164
+ $this->error("Could not create the file cache directory.");
165
+ return false;
166
+ }
167
+ }
168
+ $this->cacheDirectory = FILE_CACHE_DIRECTORY;
169
+ touch($this->cacheDirectory . '/index.php');
170
+ touch($this->cacheDirectory . '/index.html');
171
+ } else {
172
+ $this->cacheDirectory = sys_get_temp_dir();
173
+ }
174
+ //Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image.
175
+ $this->cleanCache();
176
+
177
+ $this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']);
178
+ $this->src = $this->param('src');
179
+ $this->url = parse_url($this->src);
180
+ if(strlen($this->src) <= 3){
181
+ $this->error("No image specified");
182
+ return false;
183
+ }
184
+ if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){
185
+ $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");
186
+ header('Content-Type: image/gif');
187
+ header('Content-Length: ' . sizeof($imgData));
188
+ header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
189
+ header("Pragma: no-cache");
190
+ header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
191
+ echo $imgData;
192
+ return false;
193
+ exit(0);
194
+ }
195
+ if(preg_match('/https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $this->src)){
196
+ $this->isOwnHost = true;
197
+ }
198
+ if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){
199
+ $this->debug(2, "Is a request for an external URL: " . $this->src);
200
+ $this->isURL = true;
201
+ } else {
202
+ $this->debug(2, "Is a request for an internal file: " . $this->src);
203
+ }
204
+ if($this->isURL && (! ALLOW_EXTERNAL)){
205
+ $this->error("You are not allowed to fetch images from an external website.");
206
+ return false;
207
+ }
208
+ if($this->isURL){
209
+ if(ALLOW_ALL_EXTERNAL_SITES || $this->isOwnHost){
210
+ $this->debug(2, "Fetching from all external sites is enabled or this is our own server.");
211
+ } else {
212
+ $this->debug(2, "Fetching only from selected external sites is enabled.");
213
+ $allowed = false;
214
+ foreach($ALLOWED_SITES as $site){
215
+ if (preg_match ('/(?:^|\.)' . $site . '$/i', $this->url['host'])) {
216
+ $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
217
+ $allowed = true;
218
+ }
219
+ }
220
+ if(! $allowed){
221
+ return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs.");
222
+ }
223
+ }
 
 
 
 
224
  }
225
 
226
+ $cachePrefix = ($this->isURL ? 'timthumb_ext_' : 'timthumb_int_');
227
+ if($this->isURL){
228
+ $this->cachefile = $this->cacheDirectory . '/' . $cachePrefix . md5($this->salt . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
229
+ } else {
230
+ $this->localImage = $this->getLocalImagePath($this->src);
231
+ if(! $this->localImage){
232
+ $this->error("Could not find the internal image you specified.");
233
+ return false;
234
+ }
235
+ $this->debug(1, "Local image path is {$this->localImage}");
236
+ $this->localImageMTime = @filemtime($this->localImage);
237
+ //We include the mtime of the local file in case in changes on disk.
238
+ $this->cachefile = $this->cacheDirectory . '/' . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
239
+ }
240
+ $this->debug(2, "Cache file is: " . $this->cachefile);
 
 
241
 
242
+ return true;
243
+ }
244
+ public function __destruct(){
245
+ foreach($this->toDeletes as $del){
246
+ $this->debug(2, "Deleting temp file $del");
247
+ @unlink($del);
248
+ }
249
+ }
250
+ public function run(){
251
+ if($this->isURL){
252
+ if(! ALLOW_EXTERNAL){
253
+ $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");
254
+ $this->error("You are not allowed to fetch images from an external website.");
255
+ return false;
256
+ }
257
+ $this->debug(3, "Got request for external image. Starting serveExternalImage.");
258
+ if($this->param('webshot')){
259
+ if(WEBSHOT_ENABLED){
260
+ $this->debug(3, "webshot param is set, so we're going to take a webshot.");
261
+ $this->serveWebshot();
262
+ } else {
263
+ $this->error("You added the webshot parameter but webshots are disabled on this server. You need to set WEBSHOT_ENABLED == true to enable webshots.");
264
+ }
265
+ } else {
266
+ $this->debug(3, "webshot is NOT set so we're going to try to fetch a regular image.");
267
+ $this->serveExternalImage();
268
+ }
269
+ } else {
270
+ $this->debug(3, "Got request for internal image. Starting serveInternalImage()");
271
+ $this->serveInternalImage();
272
+ }
273
+ return true;
274
+ }
275
+ protected function handleErrors(){
276
+ if($this->haveErrors()){
277
+ $this->serveErrors();
278
+ exit(0);
279
+ }
280
+ return false;
281
+ }
282
+ protected function tryBrowserCache(){
283
+ if(BROWSER_CACHE_DISABLE){ $this->debug(3, "Browser caching is disabled"); return false; }
284
+ if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){
285
+ $this->debug(3, "Got a conditional get");
286
+ $mtime = false;
287
+ //We've already checked if the real file exists in the constructor
288
+ if(! is_file($this->cachefile)){
289
+ //If we don't have something cached, regenerate the cached image.
290
+ return false;
291
+ }
292
+ if($this->localImageMTime){
293
+ $mtime = $this->localImageMTime;
294
+ $this->debug(3, "Local real file's modification time is $mtime");
295
+ } else if(is_file($this->cachefile)){ //If it's not a local request then use the mtime of the cached file to determine the 304
296
+ $mtime = @filemtime($this->cachefile);
297
+ $this->debug(3, "Cached file's modification time is $mtime");
298
+ }
299
+ if(! $mtime){ return false; }
300
 
301
+ $iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
302
+ $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");
303
+ if($iftime < 1){
304
+ $this->debug(3, "Got an invalid conditional get modified since time. Returning false.");
305
+ return false;
306
+ }
307
+ if($iftime < $mtime){ //Real file or cache file has been modified since last request, so force refetch.
308
+ $this->debug(3, "File has been modified since last fetch.");
309
+ return false;
310
+ } else { //Otherwise serve a 304
311
+ $this->debug(3, "File has not been modified since last get, so serving a 304.");
312
+ header ('HTTP/1.1 304 Not Modified');
313
+ $this->debug(1, "Returning 304 not modified");
314
+ return true;
315
+ }
316
+ }
317
+ return false;
318
+ }
319
+ protected function tryServerCache(){
320
+ $this->debug(3, "Trying server cache");
321
+ if(file_exists($this->cachefile)){
322
+ $this->debug(3, "Cachefile {$this->cachefile} exists");
323
+ if($this->isURL){
324
+ $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");
325
+ if(filesize($this->cachefile) < 1){
326
+ $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");
327
+ //Fetching error occured previously
328
+ if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){
329
+ $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");
330
+ @unlink($this->cachefile);
331
+ return false; //to indicate we didn't serve from cache and app should try and load
332
+ } else {
333
+ $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");
334
+ $this->error("An error occured fetching image.");
335
+ return false;
336
+ }
337
+ }
338
+ } else {
339
+ $this->debug(3, "Trying to serve cachefile {$this->cachefile}");
340
+ }
341
+ if($this->serveCacheFile()){
342
+ $this->debug(3, "Succesfully served cachefile {$this->cachefile}");
343
+ return true;
344
+ } else {
345
+ $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");
346
+ //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it
347
+ @unlink($this->cachefile);
348
+ return true;
349
+ }
350
+ }
351
+ }
352
+ protected function error($err){
353
+ $this->debug(3, "Adding error message: $err");
354
+ $this->errors[] = $err;
355
+ return false;
356
 
357
+ }
358
+ protected function haveErrors(){
359
+ if(sizeof($this->errors) > 0){
360
+ return true;
361
+ }
362
+ return false;
363
+ }
364
+ protected function serveErrors(){
365
+ $html = '<ul>';
366
+ foreach($this->errors as $err){
367
+ $html .= '<li>' . htmlentities($err) . '</li>';
368
+ }
369
+ $html .= '</ul>';
370
+ header ('HTTP/1.1 400 Bad Request');
371
+ echo '<h1>A TimThumb error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
372
+ echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
373
+ echo '<br />TimThumb version : ' . VERSION . '</pre>';
374
+ }
375
+ protected function serveInternalImage(){
376
+ $this->debug(3, "Local image path is $this->localImage");
377
+ if(! $this->localImage){
378
+ $this->sanityFail("localImage not set after verifying it earlier in the code.");
379
+ return false;
380
+ }
381
+ $fileSize = filesize($this->localImage);
382
+ if($fileSize > MAX_FILE_SIZE){
383
+ $this->error("The file you specified is greater than the maximum allowed file size.");
384
+ return false;
385
+ }
386
+ if($fileSize <= 0){
387
+ $this->error("The file you specified is <= 0 bytes.");
388
+ return false;
389
+ }
390
+ $this->debug(3, "Calling processImageAndWriteToCache() for local image.");
391
+ if($this->processImageAndWriteToCache($this->localImage)){
392
+ $this->serveCacheFile();
393
+ return true;
394
+ } else {
395
+ return false;
396
+ }
397
+ }
398
+ protected function cleanCache(){
399
+ $this->debug(3, "cleanCache() called");
400
+ $lastCleanFile = $this->cacheDirectory . '/timthumb_cacheLastCleanTime.touch';
401
+
402
+ //If this is a new timthumb installation we need to create the file
403
+ if(! is_file($lastCleanFile)){
404
+ $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
405
+ touch($lastCleanFile);
406
+ return;
407
+ }
408
+ if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
409
+ $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
410
+ // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
411
+ touch($lastCleanFile);
412
+ $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
413
+ $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
414
+ foreach($files as $file){
415
+ if(@filemtime($file) < $timeAgo){
416
+ $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");
417
+ @unlink($file);
418
+ }
419
+ }
420
+ return true;
421
+ } else {
422
+ $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");
423
+ }
424
+ return false;
425
+ }
426
+ protected function processImageAndWriteToCache($localImage){
427
+ $mimeType = $this->getMimeType($localImage);
428
+ $this->debug(3, "Mime type of image is $mimeType");
429
+ if(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){
430
+ return $this->error("The image being resized is not a valid gif, jpg or png.");
431
  }
432
 
433
+ if (!function_exists ('imagecreatetruecolor')) {
434
+ return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
435
+ }
436
 
437
+ if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
438
+ $imageFilters = array (
439
+ 1 => array (IMG_FILTER_NEGATE, 0),
440
+ 2 => array (IMG_FILTER_GRAYSCALE, 0),
441
+ 3 => array (IMG_FILTER_BRIGHTNESS, 1),
442
+ 4 => array (IMG_FILTER_CONTRAST, 1),
443
+ 5 => array (IMG_FILTER_COLORIZE, 4),
444
+ 6 => array (IMG_FILTER_EDGEDETECT, 0),
445
+ 7 => array (IMG_FILTER_EMBOSS, 0),
446
+ 8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),
447
+ 9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),
448
+ 10 => array (IMG_FILTER_MEAN_REMOVAL, 0),
449
+ 11 => array (IMG_FILTER_SMOOTH, 0),
450
+ );
451
+ }
452
 
453
+ // get standard input properties
454
+ $new_width = (int) abs ($this->param('w', 0));
455
+ $new_height = (int) abs ($this->param('h', 0));
456
+ $zoom_crop = (int) $this->param('zc', 1);
457
+ $quality = (int) abs ($this->param('q', 90));
458
+ $align = $this->cropTop ? 't' : $this->param('a', 'c');
459
+ $filters = $this->param('f', '');
460
+ $sharpen = (bool) $this->param('s', 0);
461
+ $canvas_color = $this->param('cc', 'ffffff');
462
+
463
+ // set default width and height if neither are set already
464
+ if ($new_width == 0 && $new_height == 0) {
465
+ $new_width = 100;
466
+ $new_height = 100;
467
+ }
468
 
469
+ // ensure size limits can not be abused
470
+ $new_width = min ($new_width, MAX_WIDTH);
471
+ $new_height = min ($new_height, MAX_HEIGHT);
472
 
473
+ // set memory limit to be able to have enough space to resize larger images
474
+ $this->setMemoryLimit();
 
 
475
 
476
+ // open the existing image
477
+ $image = $this->openImage ($mimeType, $localImage);
478
+ if ($image === false) {
479
+ return $this->error('Unable to open image.');
480
+ }
481
 
482
+ // Get original width and height
483
+ $width = imagesx ($image);
484
+ $height = imagesy ($image);
485
+ $origin_x = 0;
486
+ $origin_y = 0;
487
+
488
+ // generate new w/h if not provided
489
+ if ($new_width && !$new_height) {
490
+ $new_height = floor ($height * ($new_width / $width));
491
+ } else if ($new_height && !$new_width) {
492
+ $new_width = floor ($width * ($new_height / $height));
493
+ }
494
 
495
+ // scale down and add borders
496
+ if ($zoom_crop == 3) {
497
 
498
+ $final_height = $height * ($new_width / $width);
499
 
500
+ if ($final_height > $new_height) {
501
+ $new_width = $width * ($new_height / $height);
502
+ } else {
503
+ $new_height = $final_height;
504
+ }
505
 
506
+ }
507
 
508
+ // create a new true color image
509
+ $canvas = imagecreatetruecolor ($new_width, $new_height);
510
+ imagealphablending ($canvas, false);
511
 
512
+ if (strlen ($canvas_color) < 6) {
513
+ $canvas_color = 'ffffff';
514
+ }
515
 
516
+ $canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
517
+ $canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
518
+ $canvas_color_B = hexdec (substr ($canvas_color, 2, 2));
519
 
520
+ // Create a new transparent color for image
521
+ $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);
522
 
523
+ // Completely fill the background of the new image with allocated color.
524
+ imagefill ($canvas, 0, 0, $color);
525
 
526
+ // scale down and add borders
527
+ if ($zoom_crop == 2) {
528
 
529
+ $final_height = $height * ($new_width / $width);
 
530
 
531
+ if ($final_height > $new_height) {
 
 
 
532
 
533
+ $origin_x = $new_width / 2;
534
+ $new_width = $width * ($new_height / $height);
535
+ $origin_x = round ($origin_x - ($new_width / 2));
536
 
537
+ } else {
 
 
 
 
538
 
539
+ $origin_y = $new_height / 2;
540
+ $new_height = $final_height;
541
+ $origin_y = round ($origin_y - ($new_height / 2));
542
 
543
+ }
544
 
545
+ }
546
 
547
+ // Restore transparency blending
548
+ imagesavealpha ($canvas, true);
549
 
550
+ if ($zoom_crop > 0) {
 
551
 
552
+ $src_x = $src_y = 0;
553
+ $src_w = $width;
554
+ $src_h = $height;
555
 
556
+ $cmp_x = $width / $new_width;
557
+ $cmp_y = $height / $new_height;
558
 
559
+ // calculate x or y coordinate and width or height of source
560
+ if ($cmp_x > $cmp_y) {
561
 
562
+ $src_w = round ($width / $cmp_x * $cmp_y);
563
+ $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
 
 
 
564
 
565
+ } else if ($cmp_y > $cmp_x) {
566
 
567
+ $src_h = round ($height / $cmp_y * $cmp_x);
568
+ $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
569
 
570
+ }
 
 
 
 
 
 
571
 
572
+ // positional cropping!
573
+ if ($align) {
574
+ if (strpos ($align, 't') !== false) {
575
+ $src_y = 0;
576
+ }
577
+ if (strpos ($align, 'b') !== false) {
578
+ $src_y = $height - $src_h;
579
+ }
580
+ if (strpos ($align, 'l') !== false) {
581
+ $src_x = 0;
582
+ }
583
+ if (strpos ($align, 'r') !== false) {
584
+ $src_x = $width - $src_w;
585
+ }
586
+ }
587
 
588
+ imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
 
589
 
590
+ } else {
 
 
 
 
591
 
592
+ // copy and resize part of an image with resampling
593
+ imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
594
 
595
+ }
596
 
597
+ if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
598
+ // apply filters to image
599
+ $filterList = explode ('|', $filters);
600
+ foreach ($filterList as $fl) {
601
 
602
+ $filterSettings = explode (',', $fl);
603
+ if (isset ($imageFilters[$filterSettings[0]])) {
 
 
 
 
 
604
 
605
+ for ($i = 0; $i < 4; $i ++) {
606
+ if (!isset ($filterSettings[$i])) {
607
+ $filterSettings[$i] = null;
608
+ } else {
609
+ $filterSettings[$i] = (int) $filterSettings[$i];
610
+ }
611
+ }
612
 
613
+ switch ($imageFilters[$filterSettings[0]][1]) {
614
 
615
+ case 1:
616
 
617
+ imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
618
+ break;
619
 
620
+ case 2:
621
 
622
+ imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
623
+ break;
624
 
625
+ case 3:
626
 
627
+ imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
628
+ break;
 
 
 
 
 
629
 
630
+ case 4:
631
 
632
+ imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);
633
+ break;
634
 
635
+ default:
636
 
637
+ imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);
638
+ break;
639
 
640
+ }
641
+ }
642
+ }
643
+ }
644
 
645
+ // sharpen image
646
+ if ($sharpen && function_exists ('imageconvolution')) {
647
 
648
+ $sharpenMatrix = array (
649
+ array (-1,-1,-1),
650
+ array (-1,16,-1),
651
+ array (-1,-1,-1),
652
+ );
653
 
654
+ $divisor = 8;
655
+ $offset = 0;
656
 
657
+ imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);
658
 
659
+ }
660
+ $imgType = "";
661
+ $tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
662
+ if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){
663
+ $imgType = 'jpg';
664
+ imagejpeg($canvas, $tempfile, $quality);
665
+ } else if(preg_match('/^image\/png$/i', $mimeType)){
666
+ $imgType = 'png';
667
+ imagepng($canvas, $tempfile, floor($quality * 0.09));
668
+ } else if(preg_match('/^image\/gif$/i', $mimeType)){
669
+ $imgType = 'gif';
670
+ imagepng($canvas, $tempfile, floor($quality * 0.09));
671
+ } else {
672
+ return $this->sanityFail("Could not match mime type after verifying it previously.");
673
+ }
674
 
675
+ if( OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){
676
+ $exec = OPTIPNG_PATH;
677
+ $this->debug(3, "optipng'ing $tempfile");
678
+ $presize = filesize($tempfile);
679
+ $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down
680
+ clearstatcache();
681
+ $aftersize = filesize($tempfile);
682
+ $sizeDrop = $presize - $aftersize;
683
+ if($sizeDrop > 0){
684
+ $this->debug(1, "optipng reduced size by $sizeDrop");
685
+ } else if($sizeDrop < 0){
686
+ $this->debug(1, "optipng increased size! Difference was: $sizeDrop");
687
+ } else {
688
+ $this->debug(1, "optipng did not change image size.");
689
+ }
690
+ } else if(PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){
691
+ $exec = PNGCRUSH_PATH;
692
+ $tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
693
+ $this->debug(3, "pngcrush'ing $tempfile to $tempfile2");
694
+ $out = `$exec $tempfile $tempfile2`;
695
+ $todel = "";
696
+ if(is_file($tempfile2)){
697
+ $sizeDrop = filesize($tempfile) - filesize($tempfile2);
698
+ if($sizeDrop > 0){
699
+ $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");
700
+ $todel = $tempfile;
701
+ $tempfile = $tempfile2;
702
+ } else {
703
+ $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");
704
+ $todel = $tempfile2;
705
+ }
706
+ } else {
707
+ $this->debug(3, "pngcrush failed with output: $out");
708
+ $todel = $tempfile2;
709
+ }
710
+ @unlink($todel);
711
+ }
712
 
713
+ $this->debug(3, "Rewriting image with security header.");
714
+ $tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
715
+ $context = stream_context_create ();
716
+ $fp = fopen($tempfile,'r',0,$context);
717
+ file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type
718
+ file_put_contents($tempfile4, $fp, FILE_APPEND);
719
+ fclose($fp);
720
+ @unlink($tempfile);
721
+ $this->debug(3, "Locking and replacing cache file.");
722
+ $lockFile = $this->cachefile . '.lock';
723
+ $fh = fopen($lockFile, 'w');
724
+ if(! $fh){
725
+ return $this->error("Could not open the lockfile for writing an image.");
726
+ }
727
+ if(flock($fh, LOCK_EX)){
728
+ @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet.
729
+ rename($tempfile4, $this->cachefile);
730
+ flock($fh, LOCK_UN);
731
+ fclose($fh);
732
+ @unlink($lockFile);
733
+ } else {
734
+ fclose($fh);
735
+ @unlink($lockFile);
736
+ @unlink($tempfile4);
737
+ return $this->error("Could not get a lock for writing.");
738
+ }
739
+ $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");
740
+ imagedestroy($canvas);
741
  return true;
742
  }
743
+ protected function calcDocRoot(){
744
+ $docRoot = @$_SERVER['DOCUMENT_ROOT'];
745
+ if(!isset($docRoot)){
746
+ $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
747
+ if(isset($_SERVER['SCRIPT_FILENAME'])){
748
+ $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));
749
+ $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");
750
+ }
751
+ }
752
+ if(!isset($docRoot)){
753
+ $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");
754
+ if(isset($_SERVER['PATH_TRANSLATED'])){
755
+ $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));
756
+ $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");
757
+ }
758
+ }
759
+ if($docRoot){ $docRoot = preg_replace('/\/$/', '', $docRoot); }
760
+ $this->debug(3, "Doc root is: " . $docRoot);
761
+ $this->docRoot = $docRoot;
762
 
763
+ }
764
+ protected function getLocalImagePath($src){
765
+ $src = preg_replace('/^\//', '', $src); //strip off the leading '/'
766
+ $realDocRoot = realpath($this->docRoot); //See issue 224. Using realpath as a windows fix.
767
+ if(! $this->docRoot){
768
+ $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
769
+ //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
770
+ $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename.
771
+ if(is_file($file)){
772
+ return realpath($file);
 
 
 
 
 
 
 
773
  }
774
+ return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons.");
775
+ } //Do not go past this point without docRoot set
776
+
777
+ //Try src under docRoot
778
+ if(file_exists ($this->docRoot . '/' . $src)) {
779
+ $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
780
+ $real = realpath($this->docRoot . '/' . $src);
781
+ if(strpos($real, $realDocRoot) === 0){
782
+ return $real;
783
+ } else {
784
+ $this->debug(1, "Security block: The file specified occurs outside the document root.");
785
+ //allow search to continue
786
  }
787
+ }
788
+ //Check absolute paths and then verify the real path is under doc root
789
+ $absolute = realpath('/' . $src);
790
+ if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
791
+ $this->debug(3, "Found absolute path: $absolute");
792
+ if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
793
+ if(strpos($absolute, $realDocRoot) === 0){
794
+ return $absolute;
795
+ } else {
796
+ $this->debug(1, "Security block: The file specified occurs outside the document root.");
797
+ //and continue search
798
  }
 
799
  }
800
+ $base = $this->docRoot;
801
+ foreach (explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME'])) as $sub){
802
+ $base .= $sub . '/';
803
+ $this->debug(3, "Trying file as: " . $base . $src);
804
+ if(file_exists($base . $src)){
805
+ $this->debug(3, "Found file as: " . $base . $src);
806
+ $real = realpath($base . $src);
807
+ if(strpos($real, $realDocRoot) === 0){
808
+ return $real;
809
+ } else {
810
+ $this->debug(1, "Security block: The file specified occurs outside the document root.");
811
+ //And continue search
812
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
813
  }
814
  }
815
+ return false;
816
  }
817
+ protected function toDelete($name){
818
+ $this->debug(3, "Scheduling file $name to delete on destruct.");
819
+ $this->toDeletes[] = $name;
820
+ }
821
+ protected function serveWebshot(){
822
+ $this->debug(3, "Starting serveWebshot");
823
+ $instr = "Please follow the instructions at http://code.google.com/p/timthumb/ to set your server up for taking website screenshots.";
824
+ if(! is_file(WEBSHOT_CUTYCAPT)){
825
+ return $this->error("CutyCapt is not installed. $instr");
826
+ }
827
+ if(! is_file(WEBSHOT_XVFB)){
828
+ return $this->Error("Xvfb is not installed. $instr");
829
+ }
830
+ $cuty = WEBSHOT_CUTYCAPT;
831
+ $xv = WEBSHOT_XVFB;
832
+ $screenX = WEBSHOT_SCREEN_X;
833
+ $screenY = WEBSHOT_SCREEN_Y;
834
+ $colDepth = WEBSHOT_COLOR_DEPTH;
835
+ $format = WEBSHOT_IMAGE_FORMAT;
836
+ $timeout = WEBSHOT_TIMEOUT * 1000;
837
+ $ua = WEBSHOT_USER_AGENT;
838
+ $jsOn = WEBSHOT_JAVASCRIPT_ON ? 'on' : 'off';
839
+ $javaOn = WEBSHOT_JAVA_ON ? 'on' : 'off';
840
+ $pluginsOn = WEBSHOT_PLUGINS_ON ? 'on' : 'off';
841
+ $proxy = WEBSHOT_PROXY ? ' --http-proxy=' . WEBSHOT_PROXY : '';
842
+ $tempfile = tempnam($this->cacheDirectory, 'timthumb_webshot');
843
+ $url = $this->src;
844
+ if(! preg_match('/^https?:\/\/[a-zA-Z0-9\.\-]+/i', $url)){
845
+ return $this->error("Invalid URL supplied.");
846
+ }
847
+ $url = preg_replace('/[^A-Za-z0-9\-\.\_\~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=]+/', '', $url); //RFC 3986
848
+ //Very important we don't allow injection of shell commands here. URL is between quotes and we are only allowing through chars allowed by a the RFC
849
+ // which AFAIKT can't be used for shell injection.
850
+ if(WEBSHOT_XVFB_RUNNING){
851
+ putenv('DISPLAY=:100.0');
852
+ $command = "$cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
853
+ } else {
854
+ $command = "$xv --server-args=\"-screen 0, {$screenX}x{$screenY}x{$colDepth}\" $cuty $proxy --max-wait=$timeout --user-agent=\"$ua\" --javascript=$jsOn --java=$javaOn --plugins=$pluginsOn --js-can-open-windows=off --url=\"$url\" --out-format=$format --out=$tempfile";
855
+ }
856
+ $this->debug(3, "Executing command: $command");
857
+ $out = `$command`;
858
+ $this->debug(3, "Received output: $out");
859
+ if(! is_file($tempfile)){
860
+ return $this->error("The command to create a thumbnail failed.");
861
+ }
862
+ $this->cropTop = true;
863
+ if($this->processImageAndWriteToCache($tempfile)){
864
+ $this->debug(3, "Image processed succesfully. Serving from cache");
865
+ return $this->serveCacheFile();
866
+ } else {
867
+ return false;
868
  }
869
  }
870
+ protected function serveExternalImage(){
871
+ if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){
872
+ $this->error("Invalid URL supplied.");
873
+ return false;
874
+ }
875
+ $tempfile = tempnam($this->cacheDirectory, 'timthumb');
876
+ $this->debug(3, "Fetching external image into temporary file $tempfile");
877
+ $this->toDelete($tempfile);
878
+ #fetch file here
879
+ if(! $this->getURL($this->src, $tempfile)){
880
+ @unlink($this->cachefile);
881
+ touch($this->cachefile);
882
+ $this->debug(3, "Error fetching URL: " . $this->lastURLError);
883
+ $this->error("Error reading the URL you specified from remote host." . $this->lastURLError);
884
+ return false;
885
+ }
886
 
887
+ $mimeType = $this->getMimeType($tempfile);
888
+ if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){
889
+ $this->debug(3, "Remote file has invalid mime type: $mimeType");
890
+ @unlink($this->cachefile);
891
+ touch($this->cachefile);
892
+ $this->error("The remote file is not a valid image.");
893
+ return false;
894
+ }
895
+ if($this->processImageAndWriteToCache($tempfile)){
896
+ $this->debug(3, "Image processed succesfully. Serving from cache");
897
+ return $this->serveCacheFile();
898
+ } else {
899
+ return false;
900
+ }
901
+ }
902
+ public static function curlWrite($h, $d){
903
+ fwrite(self::$curlFH, $d);
904
+ self::$curlDataWritten += strlen($d);
905
+ if(self::$curlDataWritten > MAX_FILE_SIZE){
906
+ return 0;
907
+ } else {
908
+ return strlen($d);
909
+ }
910
+ }
911
+ protected function serveCacheFile(){
912
+ $this->debug(3, "Serving {$this->cachefile}");
913
+ if(! is_file($this->cachefile)){
914
+ $this->error("serveCacheFile called in timthumb but we couldn't find the cached file.");
915
+ return false;
916
+ }
917
+ $fp = fopen($this->cachefile, 'rb');
918
+ if(! $fp){ return $this->error("Could not open cachefile."); }
919
+ fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);
920
+ $imgType = fread($fp, 3);
921
+ fseek($fp, 3, SEEK_CUR);
922
+ if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){
923
+ @unlink($this->cachefile);
924
+ return $this->error("The cached image file seems to be corrupt.");
925
+ }
926
+ $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);
927
+ $this->sendImageHeaders($imgType, $imageDataSize);
928
+ $bytesSent = @fpassthru($fp);
929
+ fclose($fp);
930
+ if($bytesSent > 0){
931
+ return true;
932
+ }
933
+ $content = file_get_contents ($this->cachefile);
934
+ if ($content != FALSE) {
935
+ $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);
936
+ echo $content;
937
+ $this->debug(3, "Served using file_get_contents and echo");
938
+ return true;
939
+ } else {
940
+ $this->error("Cache file could not be loaded.");
941
+ return false;
942
+ }
943
+ }
944
+ protected function sendImageHeaders($mimeType, $dataSize){
945
  $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';
946
  $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';
 
947
  // send content headers then display image
948
+ header ('Content-Type: ' . $mimeType);
949
+ header ('Accept-Ranges: none'); //Changed this because we don't accept range requests
950
  header ('Last-Modified: ' . $gmdate_modified);
951
+ header ('Content-Length: ' . $dataSize);
952
+ if(BROWSER_CACHE_DISABLE){
953
+ $this->debug(3, "Browser cache is disabled so setting non-caching headers.");
954
+ header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
955
+ header("Pragma: no-cache");
956
+ header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
957
+ } else {
958
+ $this->debug(3, "Browser caching is enabled");
959
+ header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');
960
+ header('Expires: ' . $gmdate_expires);
 
961
  }
962
+ return true;
963
+ }
964
+ protected function securityChecks(){
965
+ }
966
+ protected function param($property, $default = ''){
967
+ if (isset ($_GET[$property])) {
968
+ return $_GET[$property];
969
+ } else {
970
+ return $default;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
971
  }
972
+ }
973
+ protected function openImage($mimeType, $src){
974
+ switch ($mimeType) {
975
+ case 'image/jpg':
976
+ $image = imagecreatefromjpeg ($src);
977
+ break;
978
+ case 'image/jpeg':
979
+ $image = imagecreatefromjpeg ($src);
980
+ break;
981
 
982
+ case 'image/png':
983
+ $image = imagecreatefrompng ($src);
984
+ break;
985
 
986
+ case 'image/gif':
987
+ $image = imagecreatefromgif ($src);
988
+ break;
989
+ }
990
 
991
+ return $image;
992
+ }
993
+ protected function getIP(){
994
+ $rem = @$_SERVER["REMOTE_ADDR"];
995
+ $ff = @$_SERVER["HTTP_X_FORWARDED_FOR"];
996
+ $ci = @$_SERVER["HTTP_CLIENT_IP"];
997
+ if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){
998
+ if($ff){ return $ff; }
999
+ if($ci){ return $ci; }
1000
+ return $rem;
1001
  } else {
1002
+ if($rem){ return $rem; }
1003
+ if($ff){ return $ff; }
1004
+ if($ci){ return $ci; }
1005
+ return "UNKNOWN";
1006
+ }
1007
+ }
1008
+ protected function debug($level, $msg){
1009
+ if(DEBUG_ON && $level <= DEBUG_LEVEL){
1010
+ $execTime = sprintf('%.6f', microtime(true) - $this->startTime);
1011
+ $tick = sprintf('%.6f', 0);
1012
+ if($this->lastBenchTime > 0){
1013
+ $tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime);
1014
  }
1015
+ $this->lastBenchTime = microtime(true);
1016
+ error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");
1017
  }
1018
+ }
1019
+ protected function sanityFail($msg){
1020
+ return $this->error("There is a problem in the timthumb code. Message: Please report this error at <a href='http://code.google.com/p/timthumb/issues/list'>timthumb's bug tracking page</a>: $msg");
1021
+ }
1022
+ protected function getMimeType($file){
1023
+ $info = getimagesize($file);
1024
+ if(is_array($info) && $info['mime']){
1025
+ return $info['mime'];
1026
+ }
1027
+ return '';
1028
+ }
1029
+ protected function setMemoryLimit(){
1030
+ $inimem = ini_get('memory_limit');
1031
+ $inibytes = timthumb::returnBytes($inimem);
1032
+ $ourbytes = timthumb::returnBytes(MEMORY_LIMIT);
1033
+ if($inibytes < $ourbytes){
1034
+ ini_set ('memory_limit', MEMORY_LIMIT);
1035
+ $this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT);
1036
+ } else {
1037
+ $this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller.");
1038
+ }
1039
+ }
1040
+ protected static function returnBytes($size_str){
1041
+ switch (substr ($size_str, -1))
1042
+ {
1043
+ case 'M': case 'm': return (int)$size_str * 1048576;
1044
+ case 'K': case 'k': return (int)$size_str * 1024;
1045
+ case 'G': case 'g': return (int)$size_str * 1073741824;
1046
+ default: return $size_str;
1047
+ }
1048
+ }
1049
+ protected function getURL($url, $tempfile){
1050
+ $this->lastURLError = false;
1051
+ $url = preg_replace('/ /', '%20', $url);
1052
+ if(function_exists('curl_init')){
1053
+ $this->debug(3, "Curl is installed so using it to fetch URL.");
1054
+ self::$curlFH = fopen($tempfile, 'w');
1055
+ if(! self::$curlFH){
1056
+ $this->error("Could not open $tempfile for writing.");
1057
+ return false;
1058
+ }
1059
+ self::$curlDataWritten = 0;
1060
+ $this->debug(3, "Fetching url with curl: $url");
1061
+ $curl = curl_init($url);
1062
+ curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
1063
+ curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");
1064
+ curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE);
1065
+ curl_setopt ($curl, CURLOPT_HEADER, 0);
1066
+ curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
1067
+ curl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite');
1068
+ @curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true);
1069
+ @curl_setopt ($curl, CURLOPT_MAXREDIRS, 10);
1070
+
1071
+ $curlResult = curl_exec($curl);
1072
+ fclose(self::$curlFH);
1073
+
1074
+ if($curlResult){
1075
+ curl_close($curl);
1076
+ return true;
1077
+ } else {
1078
+ $this->lastURLError = curl_error($curl);
1079
+ curl_close($curl);
1080
+ return false;
1081
  }
 
 
 
1082
  } else {
1083
+ $img = @file_get_contents ($url);
1084
+ if($img === false){
1085
+ $this->lastURLError = error_get_last();
1086
+ return false;
1087
+ }
1088
+ if(! file_put_contents($tempfile, $img)){
1089
+ $this->error("Could not write to $tempfile.");
1090
+ return false;
1091
+ }
1092
+ return true;
1093
  }
1094
 
1095
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1096
  }
1097
+ ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: http://ilovecode.ru/donate/
4
  Tags: shortcode, shortcodes, short code, shortcodes, tab, tabs, button, buttons, jquery, box, boxes, toggle, spoiler, column, columns, services, service, pullquote, list, lists, frame, images, image, links, fancy, fancy link, fancy links, fancy buttons, jquery tabs, accordeon, slider, nivo, nivo slider, plugin, admin, photoshop, gallery, bloginfo, list pages, sub pages, navigation, siblings pages, children pages, permalink, permalinks, feed, document, member, members, documents, jcarousel, rss
5
  Requires at least: 3.0
6
  Tested up to: 3.2.9
7
- Stable tag: 2.7.0
8
 
9
  Provides support for multiple useful shortcodes
10
 
@@ -13,44 +13,18 @@ Provides support for multiple useful shortcodes
13
 
14
  With this plugin you can easily add buttons, dividers, spacers, boxes, notes and much more
15
 
16
- = Complete list of available shortcodes =
17
- * Heading
18
- * Frame
19
- * Tabs
20
- * Spoiler
21
- * Divider
22
- * Spacer
23
- * Quote
24
- * Pullquote
25
- * Highlight
26
- * Permalink
27
- * Bloginfo
28
- * Button
29
- * Fancy link
30
- * Service
31
- * Box
32
- * Note
33
- * Menu
34
- * Subpages
35
- * Siblings
36
- * List
37
- * Column
38
- * Table
39
- * Media
40
- * Members
41
- * Nivo slider
42
- * jCarousel
43
- * Photoshop
44
- * Feed
45
- * Document
46
-
47
- = Have a bug? =
48
  Forum - http://wordpress.org/tags/shortcodes-ultimate?forum_id=10
49
  Author blog - http://ilovecode.ru/?p=122
50
  Twitter: http://twitter.com/gn_themes
51
 
52
  = Thanks for translations =
53
- French translation - Aurélien DENIS [ http://wpchannel.com/ ]
54
 
55
  Have a translation? Contact me - ano.vladimir@gmail.com
56
 
@@ -77,12 +51,22 @@ Upgrade normally via your Wordpress admin -> Plugins panel.
77
 
78
  == Frequently Asked Questions ==
79
 
80
- = Complete list of supported shortcodes =
81
- See your dashboard
 
 
 
 
 
 
82
 
83
 
84
  == Changelog ==
85
 
 
 
 
 
86
  = 2.5 =
87
  * Theme integration
88
 
4
  Tags: shortcode, shortcodes, short code, shortcodes, tab, tabs, button, buttons, jquery, box, boxes, toggle, spoiler, column, columns, services, service, pullquote, list, lists, frame, images, image, links, fancy, fancy link, fancy links, fancy buttons, jquery tabs, accordeon, slider, nivo, nivo slider, plugin, admin, photoshop, gallery, bloginfo, list pages, sub pages, navigation, siblings pages, children pages, permalink, permalinks, feed, document, member, members, documents, jcarousel, rss
5
  Requires at least: 3.0
6
  Tested up to: 3.2.9
7
+ Stable tag: 3.0.0
8
 
9
  Provides support for multiple useful shortcodes
10
 
13
 
14
  With this plugin you can easily add buttons, dividers, spacers, boxes, notes and much more
15
 
16
+ = In new version (3.0) =
17
+ * New shortcode: private - private notes for editors
18
+ * Patched and secure timthumb.php
19
+ * Long-awaited button for WYSIWIG editor (search it near Upload/Insert buttons) (beta feature)
20
+
21
+ = Bug? =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  Forum - http://wordpress.org/tags/shortcodes-ultimate?forum_id=10
23
  Author blog - http://ilovecode.ru/?p=122
24
  Twitter: http://twitter.com/gn_themes
25
 
26
  = Thanks for translations =
27
+ Fr - Aurélien DENIS [ http://wpchannel.com/ ]
28
 
29
  Have a translation? Contact me - ano.vladimir@gmail.com
30
 
51
 
52
  == Frequently Asked Questions ==
53
 
54
+ = Compatibility mode =
55
+ This mode adds a prefix to all plugin shortcodes
56
+ [button] => [gn_button]
57
+ [tabs] => [gn_tabs]
58
+ [tab] => [gn_tab]
59
+
60
+ = WYSIWYG button =
61
+ Search it near Upload/Insert buttons
62
 
63
 
64
  == Changelog ==
65
 
66
+ = 2.7 =
67
+ * French translation
68
+ * Fixed for work with new jQuery 1.6 in WP 3.2
69
+
70
  = 2.5 =
71
  * Theme integration
72
 
shortcodes-ultimate.php CHANGED
@@ -1,9 +1,8 @@
1
  <?php
2
-
3
  /*
4
  Plugin Name: Shortcodes Ultimate
5
  Plugin URI: http://ilovecode.ru/?p=122
6
- Version: 2.7.0
7
  Author: Vladimir Anokhin
8
  Author URI: http://ilovecode.ru/
9
  Description: Provides support for many easy to use shortcodes
@@ -49,6 +48,7 @@
49
  // Register styles
50
  wp_register_style( 'shortcodes-ultimate', su_plugin_url() . '/css/style.css', false, su_get_version(), 'all' );
51
  wp_register_style( 'shortcodes-ultimate-admin', su_plugin_url() . '/css/admin.css', false, su_get_version(), 'all' );
 
52
  wp_register_style( 'nivo-slider', su_plugin_url() . '/css/nivoslider.css', false, su_get_version(), 'all' );
53
  wp_register_style( 'jcarousel', su_plugin_url() . '/css/jcarousel.css', false, su_get_version(), 'all' );
54
  wp_register_style( 'codemirror', su_plugin_url() . '/css/codemirror.css', false, su_get_version(), 'all' );
@@ -57,6 +57,7 @@
57
  // Register scripts
58
  wp_register_script( 'shortcodes-ultimate', su_plugin_url() . '/js/init.js', false, su_get_version(), false );
59
  wp_register_script( 'shortcodes-ultimate-admin', su_plugin_url() . '/js/admin.js', false, su_get_version(), false );
 
60
  wp_register_script( 'nivo-slider', su_plugin_url() . '/js/nivoslider.js', false, su_get_version(), false );
61
  wp_register_script( 'jcarousel', su_plugin_url() . '/js/jcarousel.js', false, su_get_version(), false );
62
  wp_register_script( 'codemirror', su_plugin_url() . '/js/codemirror.js', false, su_get_version(), false );
@@ -115,6 +116,21 @@
115
  wp_enqueue_script( 'shortcodes-ultimate-admin' );
116
  }
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  // Register shortcodes
119
  foreach ( su_shortcodes() as $shortcode => $params ) {
120
  add_shortcode( su_compatibility_mode_prefix() . $shortcode, 'su_' . $shortcode . '_shortcode' );
@@ -268,4 +284,40 @@
268
  }
269
  }
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  ?>
1
  <?php
 
2
  /*
3
  Plugin Name: Shortcodes Ultimate
4
  Plugin URI: http://ilovecode.ru/?p=122
5
+ Version: 3.0.0
6
  Author: Vladimir Anokhin
7
  Author URI: http://ilovecode.ru/
8
  Description: Provides support for many easy to use shortcodes
48
  // Register styles
49
  wp_register_style( 'shortcodes-ultimate', su_plugin_url() . '/css/style.css', false, su_get_version(), 'all' );
50
  wp_register_style( 'shortcodes-ultimate-admin', su_plugin_url() . '/css/admin.css', false, su_get_version(), 'all' );
51
+ wp_register_style( 'shortcodes-ultimate-generator', su_plugin_url() . '/css/generator.css', false, su_get_version(), 'all' );
52
  wp_register_style( 'nivo-slider', su_plugin_url() . '/css/nivoslider.css', false, su_get_version(), 'all' );
53
  wp_register_style( 'jcarousel', su_plugin_url() . '/css/jcarousel.css', false, su_get_version(), 'all' );
54
  wp_register_style( 'codemirror', su_plugin_url() . '/css/codemirror.css', false, su_get_version(), 'all' );
57
  // Register scripts
58
  wp_register_script( 'shortcodes-ultimate', su_plugin_url() . '/js/init.js', false, su_get_version(), false );
59
  wp_register_script( 'shortcodes-ultimate-admin', su_plugin_url() . '/js/admin.js', false, su_get_version(), false );
60
+ wp_register_script( 'shortcodes-ultimate-generator', su_plugin_url() . '/js/generator.js', false, su_get_version(), false );
61
  wp_register_script( 'nivo-slider', su_plugin_url() . '/js/nivoslider.js', false, su_get_version(), false );
62
  wp_register_script( 'jcarousel', su_plugin_url() . '/js/jcarousel.js', false, su_get_version(), false );
63
  wp_register_script( 'codemirror', su_plugin_url() . '/js/codemirror.js', false, su_get_version(), false );
116
  wp_enqueue_script( 'shortcodes-ultimate-admin' );
117
  }
118
 
119
+ // Scipts and stylesheets for editing pages (shortcode generator popup)
120
+ elseif ( is_admin() ) {
121
+
122
+ // Get current page type
123
+ global $pagenow;
124
+
125
+ if ( $pagenow == 'post.php' || $pagenow == 'edit.php' || $pagenow == 'post-new.php' ) {
126
+ // Enqueue styles
127
+ wp_enqueue_style( 'shortcodes-ultimate-generator' );
128
+
129
+ // Enqueue scripts
130
+ wp_enqueue_script( 'shortcodes-ultimate-generator' );
131
+ }
132
+ }
133
+
134
  // Register shortcodes
135
  foreach ( su_shortcodes() as $shortcode => $params ) {
136
  add_shortcode( su_compatibility_mode_prefix() . $shortcode, 'su_' . $shortcode . '_shortcode' );
284
  }
285
  }
286
 
287
+ /**
288
+ * Add generator button to Upload/Insert buttons
289
+ */
290
+ function su_add_generator_button() {
291
+ echo '<a href="#TB_inline?width=640&height=500&inlineId=su-generator-wrap" class="thickbox" title="' . __( 'Insert shortcode', 'shortcodes-ultimate' ) . '"><img src="' . su_plugin_url() . '/images/admin/media-icon.png" alt="" /></a>';
292
+ }
293
+
294
+ add_action( 'media_buttons', 'su_add_generator_button', 20 );
295
+
296
+ /**
297
+ * Generator popup box
298
+ */
299
+ function su_generator_popup() {
300
+ ?>
301
+ <div id="su-generator-wrap" style="display:none">
302
+ <div id="su-generator">
303
+ <p>
304
+ <select id="su-generator-select">
305
+ <option value="false"><?php _e( 'Select shortcode', 'shortcodes-ultimate' ); ?></option>
306
+ <?
307
+ foreach ( su_shortcodes() as $name => $shortcode ) {
308
+ ?>
309
+ <option value="<?php echo $name; ?>"><?php echo $shortcode['name']; ?></option>
310
+ <?php
311
+ }
312
+ ?>
313
+ </select>
314
+ </p>
315
+ <div id="su-generator-settings"></div>
316
+ <input type="hidden" name="su-generator-url" id="su-generator-url" value="<?php echo su_plugin_url(); ?>" />
317
+ </div>
318
+ </div>
319
+ <?php
320
+ }
321
+
322
+ add_action( 'admin_footer', 'su_generator_popup' );
323
  ?>