NextGEN Gallery – WordPress Gallery Plugin - Version 3.13

Version Description

  • 08.04.2021
  • Fixed: All WP-Admin links had "/wp-admin/" removed for some users
Download this release

Release Info

Developer photocrati
Plugin Icon 128x128 NextGEN Gallery – WordPress Gallery Plugin
Version 3.13
Comparing to
See all releases

Code changes from version 3.12 to 3.13

Files changed (188) hide show
  1. changelog.txt +3 -0
  2. composer.lock +6 -6
  3. nggallery.php +2 -2
  4. phpcs.xml.dist +0 -22
  5. products/photocrati_nextgen/modules/cache/package.module.cache.php +1 -5
  6. products/photocrati_nextgen/modules/datamapper/package.module.datamapper.php +1127 -1127
  7. products/photocrati_nextgen/modules/fs/package.module.fs.php +79 -83
  8. products/photocrati_nextgen/modules/i18n/module.i18n.php +0 -10
  9. products/photocrati_nextgen/modules/i18n/package.module.i18n.php +0 -90
  10. products/photocrati_nextgen/modules/lightbox/package.module.lightbox.php +1 -6
  11. products/photocrati_nextgen/modules/marketing/static/pro-mosaic-preview.jpg +0 -0
  12. products/photocrati_nextgen/modules/mvc/package.module.mvc.php +88 -90
  13. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/CHANGELOG.md +0 -0
  14. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/LICENSE.md +0 -0
  15. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/css/select2.css +0 -0
  16. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/css/select2.min.css +0 -0
  17. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/af.js +0 -0
  18. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/af.min.js +0 -0
  19. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ar.js +0 -0
  20. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ar.min.js +0 -0
  21. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/az.js +0 -0
  22. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/az.min.js +0 -0
  23. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bg.js +0 -0
  24. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bg.min.js +0 -0
  25. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bn.js +0 -0
  26. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bn.min.js +0 -0
  27. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bs.js +0 -0
  28. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bs.min.js +0 -0
  29. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ca.js +0 -0
  30. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ca.min.js +0 -0
  31. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/cs.js +0 -0
  32. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/cs.min.js +0 -0
  33. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/da.js +0 -0
  34. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/da.min.js +0 -0
  35. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/de.js +0 -0
  36. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/de.min.js +0 -0
  37. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/dsb.js +0 -0
  38. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/dsb.min.js +0 -0
  39. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/el.js +0 -0
  40. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/el.min.js +0 -0
  41. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/en.js +0 -0
  42. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/en.min.js +0 -0
  43. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/es.js +0 -0
  44. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/es.min.js +0 -0
  45. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/et.js +0 -0
  46. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/et.min.js +0 -0
  47. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/eu.js +0 -0
  48. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/eu.min.js +0 -0
  49. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fa.js +0 -0
  50. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fa.min.js +0 -0
  51. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fi.js +0 -0
  52. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fi.min.js +0 -0
  53. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fr.js +0 -0
  54. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fr.min.js +0 -0
  55. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/gl.js +0 -0
  56. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/gl.min.js +0 -0
  57. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/he.js +0 -0
  58. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/he.min.js +0 -0
  59. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hi.js +0 -0
  60. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hi.min.js +0 -0
  61. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hr.js +0 -0
  62. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hr.min.js +0 -0
  63. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hsb.js +0 -0
  64. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hsb.min.js +0 -0
  65. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hu.js +0 -0
  66. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hu.min.js +0 -0
  67. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hy.js +0 -0
  68. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hy.min.js +0 -0
  69. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/id.js +0 -0
  70. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/id.min.js +0 -0
  71. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/is.js +0 -0
  72. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/is.min.js +0 -0
  73. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/it.js +0 -0
  74. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/it.min.js +0 -0
  75. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ja.js +0 -0
  76. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ja.min.js +0 -0
  77. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ka.js +0 -0
  78. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ka.min.js +0 -0
  79. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/km.js +0 -0
  80. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/km.min.js +0 -0
  81. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ko.js +0 -0
  82. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ko.min.js +0 -0
  83. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lt.js +0 -0
  84. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lt.min.js +0 -0
  85. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lv.js +0 -0
  86. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lv.min.js +0 -0
  87. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/mk.js +0 -0
  88. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/mk.min.js +0 -0
  89. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ms.js +0 -0
  90. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ms.min.js +0 -0
  91. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nb.js +0 -0
  92. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nb.min.js +0 -0
  93. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ne.js +0 -0
  94. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ne.min.js +0 -0
  95. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nl.js +0 -0
  96. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nl.min.js +0 -0
  97. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pl.js +0 -0
  98. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pl.min.js +0 -0
  99. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ps.js +0 -0
  100. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ps.min.js +0 -0
  101. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt-BR.js +0 -0
  102. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt-BR.min.js +0 -0
  103. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt.js +0 -0
  104. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt.min.js +0 -0
  105. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ro.js +0 -0
  106. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ro.min.js +0 -0
  107. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ru.js +0 -0
  108. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ru.min.js +0 -0
  109. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sk.js +0 -0
  110. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sk.min.js +0 -0
  111. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sl.js +0 -0
  112. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sl.min.js +0 -0
  113. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sq.js +0 -0
  114. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sq.min.js +0 -0
  115. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr-Cyrl.js +0 -0
  116. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr-Cyrl.min.js +0 -0
  117. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr.js +0 -0
  118. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr.min.js +0 -0
  119. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sv.js +0 -0
  120. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sv.min.js +0 -0
  121. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/th.js +0 -0
  122. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/th.min.js +0 -0
  123. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tk.js +0 -0
  124. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tk.min.js +0 -0
  125. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tr.js +0 -0
  126. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tr.min.js +0 -0
  127. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/uk.js +0 -0
  128. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/uk.min.js +0 -0
  129. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/vi.js +0 -0
  130. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/vi.min.js +0 -0
  131. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-CN.js +0 -0
  132. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-CN.min.js +0 -0
  133. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-TW.js +0 -0
  134. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-TW.min.js +0 -0
  135. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full copy.js +0 -0
  136. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full copy.min.js +0 -0
  137. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full.js +0 -0
  138. products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full.min.js +0 -0
  139. products/photocrati_nextgen/modules/nextgen_basic_album/package.module.nextgen_basic_album.php +3 -3
  140. products/photocrati_nextgen/modules/nextgen_basic_gallery/module.nextgen_basic_gallery.php +1 -1
  141. products/photocrati_nextgen/modules/nextgen_basic_gallery/package.module.nextgen_basic_gallery.php +2 -2
  142. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/ajax-loader.gif +0 -0
  143. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/config.rb +0 -0
  144. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.eot +0 -0
  145. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.svg +0 -0
  146. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.ttf +0 -0
  147. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.woff +0 -0
  148. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-1.8.0-modded.js +0 -0
  149. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-1.8.0-modded.min.js +0 -0
  150. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.css +0 -0
  151. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.less +0 -0
  152. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.min.css +0 -0
  153. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.scss +0 -0
  154. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.css +0 -0
  155. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.less +0 -0
  156. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.min.css +0 -0
  157. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.scss +0 -0
  158. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow_preview.jpg +0 -0
  159. products/photocrati_nextgen/modules/nextgen_basic_gallery/static/thumb_preview.jpg +0 -0
  160. products/photocrati_nextgen/modules/nextgen_basic_imagebrowser/module.nextgen_basic_imagebrowser.php +1 -1
  161. products/photocrati_nextgen/modules/nextgen_basic_imagebrowser/static/preview.jpg +0 -0
  162. products/photocrati_nextgen/modules/nextgen_basic_tagcloud/module.nextgen_basic_tagcloud.php +1 -1
  163. products/photocrati_nextgen/modules/nextgen_basic_tagcloud/package.module.nextgen_basic_tagcloud.php +2 -2
  164. products/photocrati_nextgen/modules/nextgen_basic_tagcloud/static/preview.gif +0 -0
  165. products/photocrati_nextgen/modules/nextgen_data/module.nextgen_data.php +0 -2
  166. products/photocrati_nextgen/modules/nextgen_data/package.module.nextgen_data.php +3936 -3923
  167. products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php +150 -159
  168. products/photocrati_nextgen/modules/nextgen_other_options/package.module.nextgen_other_options.php +2 -2
  169. products/photocrati_nextgen/modules/ngglegacy/fonts/YanoneKaffeesatz-Bold.ttf +0 -0
  170. products/photocrati_nextgen/modules/router/module.router.php +1 -1
  171. products/photocrati_nextgen/modules/router/package.module.router.php +5 -5
  172. products/photocrati_nextgen/modules/security/package.module.security.php +0 -32
  173. products/photocrati_nextgen/modules/widget/package.module.widget.php +1 -5
  174. products/photocrati_nextgen/modules/wordpress_routing/package.module.wordpress_routing.php +2 -2
  175. readme.txt +4 -1
  176. vendor/autoload.php +1 -1
  177. vendor/composer/autoload_real.php +7 -7
  178. vendor/composer/autoload_static.php +3 -3
  179. vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README +0 -0
  180. vendor/imagely/pope-framework/README.txt +0 -0
  181. vendor/imagely/pope-framework/lib/autoload.php +0 -0
  182. vendor/imagely/pope-framework/lib/class.base_module.php +14 -14
  183. vendor/imagely/pope-framework/lib/class.base_product.php +0 -0
  184. vendor/imagely/pope-framework/lib/class.component.php +0 -0
  185. vendor/imagely/pope-framework/lib/class.component_factory.php +0 -0
  186. vendor/imagely/pope-framework/lib/class.component_registry.php +31 -28
  187. vendor/imagely/pope-framework/lib/class.extensibleobject.php +0 -0
  188. vendor/imagely/pope-framework/lib/interface.component_factory.php +0 -0
changelog.txt CHANGED
@@ -1,6 +1,9 @@
1
  NextGEN Gallery
2
  by Imagely
3
 
 
 
 
4
  = V3.12 - 07.13.2021
5
  * Fixed: PHP warning generated for some Nimble Builder users
6
  * Changed: Added 'ngg_marketing_parameters' filter
1
  NextGEN Gallery
2
  by Imagely
3
 
4
+ = V3.13 - 08.04.2021
5
+ * Fixed: All WP-Admin links had "/wp-admin/" removed for some users
6
+
7
  = V3.12 - 07.13.2021
8
  * Fixed: PHP warning generated for some Nimble Builder users
9
  * Changed: Added 'ngg_marketing_parameters' filter
composer.lock CHANGED
@@ -109,16 +109,16 @@
109
  "packages-dev": [
110
  {
111
  "name": "nikic/php-parser",
112
- "version": "v4.11.0",
113
  "source": {
114
  "type": "git",
115
  "url": "https://github.com/nikic/PHP-Parser.git",
116
- "reference": "fe14cf3672a149364fb66dfe11bf6549af899f94"
117
  },
118
  "dist": {
119
  "type": "zip",
120
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/fe14cf3672a149364fb66dfe11bf6549af899f94",
121
- "reference": "fe14cf3672a149364fb66dfe11bf6549af899f94",
122
  "shasum": "",
123
  "mirrors": [
124
  {
@@ -165,9 +165,9 @@
165
  ],
166
  "support": {
167
  "issues": "https://github.com/nikic/PHP-Parser/issues",
168
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.11.0"
169
  },
170
- "time": "2021-07-03T13:36:55+00:00"
171
  }
172
  ],
173
  "aliases": [],
109
  "packages-dev": [
110
  {
111
  "name": "nikic/php-parser",
112
+ "version": "v4.12.0",
113
  "source": {
114
  "type": "git",
115
  "url": "https://github.com/nikic/PHP-Parser.git",
116
+ "reference": "6608f01670c3cc5079e18c1dab1104e002579143"
117
  },
118
  "dist": {
119
  "type": "zip",
120
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143",
121
+ "reference": "6608f01670c3cc5079e18c1dab1104e002579143",
122
  "shasum": "",
123
  "mirrors": [
124
  {
165
  ],
166
  "support": {
167
  "issues": "https://github.com/nikic/PHP-Parser/issues",
168
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0"
169
  },
170
+ "time": "2021-07-21T10:44:31+00:00"
171
  }
172
  ],
173
  "aliases": [],
nggallery.php CHANGED
@@ -4,7 +4,7 @@ if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You
4
  /**
5
  * Plugin Name: NextGEN Gallery
6
  * Description: The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 30 million downloads.
7
- * Version: 3.12
8
  * Author: Imagely
9
  * Plugin URI: https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/
10
  * Author URI: https://www.imagely.com
@@ -712,7 +712,7 @@ class C_NextGEN_Bootstrap
712
  define('NGG_PRODUCT_URL', path_join(str_replace("\\" , '/', NGG_PLUGIN_URL), 'products'));
713
  define('NGG_MODULE_URL', path_join(str_replace("\\", '/', NGG_PRODUCT_URL), 'photocrati_nextgen/modules'));
714
  define('NGG_PLUGIN_STARTED_AT', microtime());
715
- define('NGG_PLUGIN_VERSION', '3.12');
716
 
717
  define(
718
  'NGG_SCRIPT_VERSION',
4
  /**
5
  * Plugin Name: NextGEN Gallery
6
  * Description: The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 30 million downloads.
7
+ * Version: 3.13
8
  * Author: Imagely
9
  * Plugin URI: https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/
10
  * Author URI: https://www.imagely.com
712
  define('NGG_PRODUCT_URL', path_join(str_replace("\\" , '/', NGG_PLUGIN_URL), 'products'));
713
  define('NGG_MODULE_URL', path_join(str_replace("\\", '/', NGG_PRODUCT_URL), 'photocrati_nextgen/modules'));
714
  define('NGG_PLUGIN_STARTED_AT', microtime());
715
+ define('NGG_PLUGIN_VERSION', '3.13');
716
 
717
  define(
718
  'NGG_SCRIPT_VERSION',
phpcs.xml.dist DELETED
@@ -1,22 +0,0 @@
1
- <?xml version="1.0"?>
2
- <ruleset name="Block Scaffolding Coding Standards">
3
- <arg name="extensions" value="php" />
4
- <arg name="colors" />
5
- <arg value="s" /><!-- Show sniff codes in all reports -->
6
-
7
- <rule ref="WordPress-Core">
8
- <exclude name="WordPress.Files.FileName" />
9
- <exclude name="Generic.Arrays.DisallowShortArraySyntax" />
10
- </rule>
11
-
12
- <rule ref="WordPress-Docs"></rule>
13
-
14
- <rule ref="PHPCompatibilityWP" />
15
- <config name="testVersion" value="5.6-" />
16
-
17
- <file>.</file>
18
-
19
- <exclude-pattern>/node_modules/</exclude-pattern>
20
- <exclude-pattern>/vendor/</exclude-pattern>
21
- <exclude-pattern>/js/dist/editor.asset.php</exclude-pattern> <!-- this is generated by 'npm run build' -->
22
- </ruleset>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
products/photocrati_nextgen/modules/cache/package.module.cache.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  * Class C_Cache
4
- * @mixin Mixin_Cache
5
  * @implements I_Cache
6
  */
7
  class C_Cache extends C_Component
@@ -10,7 +10,6 @@ class C_Cache extends C_Component
10
  function define($context = FALSE)
11
  {
12
  parent::define($context);
13
- $this->add_mixin('Mixin_Cache');
14
  $this->implement('I_Cache');
15
  }
16
  /**
@@ -24,9 +23,6 @@ class C_Cache extends C_Component
24
  }
25
  return self::$_instances[$context];
26
  }
27
- }
28
- class Mixin_Cache extends Mixin
29
- {
30
  /**
31
  * Empties a directory of all of its content
32
  *
1
  <?php
2
  /**
3
  * Class C_Cache
4
+ *
5
  * @implements I_Cache
6
  */
7
  class C_Cache extends C_Component
10
  function define($context = FALSE)
11
  {
12
  parent::define($context);
 
13
  $this->implement('I_Cache');
14
  }
15
  /**
23
  }
24
  return self::$_instances[$context];
25
  }
 
 
 
26
  /**
27
  * Empties a directory of all of its content
28
  *
products/photocrati_nextgen/modules/datamapper/package.module.datamapper.php CHANGED
@@ -24,724 +24,696 @@ class A_DataMapper_Factory extends Mixin
24
  }
25
  }
26
  /**
27
- * Provides instance methods for C_CustomPost_DataMapper_Driver
28
- * @mixin C_CustomPost_DataMapper_Driver
 
29
  */
30
- class Mixin_CustomPost_DataMapper_Driver extends Mixin
31
  {
32
- /**
33
- * Returns a list of querable table columns for posts
34
- * @return array
35
- */
36
- function _get_querable_table_columns()
 
37
  {
38
- return array('name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count');
 
 
 
39
  }
40
- /**
41
- * Used to select which fields should be returned. NOT currently used by
42
- * this implementation of the datamapper driver
43
- * @param string $fields
44
- * @return C_DataMapper_Driver_Base
45
- */
46
- function select($fields = '*')
47
  {
48
- $this->object->_query_args = array('post_type' => $this->object->get_object_name(), 'paged' => FALSE, 'fields' => $fields, 'post_status' => 'any', 'datamapper' => TRUE, 'posts_per_page' => -1, 'is_select' => TRUE, 'is_delete' => FALSE);
49
- return $this->object;
 
 
 
 
50
  }
51
  /**
52
- * Specifies an order clause
53
- * @param string $order_by
54
- * @param string $direction
55
- * @return C_DataMapper_Driver_Base
56
  */
57
- function order_by($order_by, $direction = 'ASC')
58
  {
59
- // Make an exception for the rand() method
60
- $order_by = preg_replace("/rand\\(\\s*\\)/", 'rand', $order_by);
61
- if (in_array($order_by, $this->object->_get_querable_table_columns())) {
62
- $this->object->_query_args['orderby'] = $order_by;
63
- } else {
64
- // ordering by a meta value
65
- $this->object->_query_args['orderby'] = 'meta_value';
66
- $this->object->_query_args['meta_key'] = $order_by;
67
- }
68
- $this->object->_query_args['order'] = $direction;
69
- return $this->object;
70
  }
71
  /**
72
- * Specifies a limit and optional offset
73
- * @param int $max
74
- * @param int|bool $offset (optional)
75
- * @return object
76
  */
77
- function limit($max, $offset = FALSE)
78
  {
79
- if ($max) {
80
- $this->object->_query_args['paged'] = TRUE;
81
- if ($offset) {
82
- $this->object->_query_args['offset'] = $offset;
83
- } else {
84
- unset($this->object->_query_args['offset']);
85
- }
86
- $this->object->_query_args['posts_per_page'] = $max;
87
  }
88
- return $this->object;
89
  }
90
  /**
91
- * Specifies a list of columns to group by
92
- * @param array|string $columns
93
- * @return object
94
  */
95
- function group_by($columns = array())
96
  {
97
- if (!isset($this->object->_query_args['group_by_columns'])) {
98
- $this->object->_query_args['group_by_columns'] = $columns;
99
- } else {
100
- $this->object->_query_args['group_by_columns'] = array_merge($this->object->_query_args['group_by_columns'], $columns);
 
101
  }
102
- return $this->object;
103
  }
104
  /**
105
- * Adds a WP_Query where clause
106
- * @param array $where_clauses
107
- * @param string $join
108
  */
109
- function _add_where_clause($where_clauses, $join)
110
  {
111
- foreach ($where_clauses as $clause) {
112
- // $clause => array(
113
- // 'column' => 'ID',
114
- // 'value' => 1210,
115
- // 'compare' => '='
116
- // )
117
- // Determine where what the where clause is comparing
118
- switch ($clause['column']) {
119
- case 'author':
120
- case 'author_id':
121
- $this->object->_query_args['author'] = $clause['value'];
122
- break;
123
- case 'author_name':
124
- $this->object->_query_args['author_name'] = $clause['value'];
125
- break;
126
- case 'cat':
127
- case 'cat_id':
128
- case 'category_id':
129
- switch ($clause['compare']) {
130
- case '=':
131
- case 'BETWEEN':
132
- case 'IN':
133
- if (!isset($this->object->_query_args['category__in'])) {
134
- $this->object->_query_args['category__in'] = array();
135
- }
136
- $this->object->_query_args['category__in'][] = $clause['value'];
137
- break;
138
- case '!=':
139
- case 'NOT BETWEEN':
140
- case 'NOT IN':
141
- if (!isset($this->object->_query_args['category__not_in'])) {
142
- $this->object->_query_args['category__not_in'] = array();
143
- }
144
- $this->object->_query_args['category__not_in'][] = $clause['value'];
145
- break;
146
- }
147
- break;
148
- case 'category_name':
149
- $this->object->_query_args['category_name'] = $clause['value'];
150
- break;
151
- case 'post_id':
152
- case $this->object->get_primary_key_column():
153
- switch ($clause['compare']) {
154
- case '=':
155
- case 'IN':
156
- case 'BETWEEN':
157
- if (!isset($this->object->_query_args['post__in'])) {
158
- $this->object->_query_args['post__in'] = array();
159
- }
160
- $this->object->_query_args['post__in'][] = $clause['value'];
161
- break;
162
- default:
163
- if (!isset($this->object->_query_args['post__not_in'])) {
164
- $this->object->_query_args['post__not_in'] = array();
165
- }
166
- $this->object->_query_args['post__not_in'][] = $clause['value'];
167
- break;
168
- }
169
- break;
170
- case 'pagename':
171
- case 'postname':
172
- case 'page_name':
173
- case 'post_name':
174
- if ($clause['compare'] == 'LIKE') {
175
- $this->object->_query_args['page_name__like'] = $clause['value'];
176
- } elseif ($clause['compare'] == '=') {
177
- $this->object->_query_args['pagename'] = $clause['value'];
178
- } elseif ($clause['compare'] == 'IN') {
179
- $this->object->_query_args['page_name__in'] = $clause['value'];
180
- }
181
- break;
182
- case 'post_title':
183
- // Post title uses custom WHERE clause
184
- if ($clause['compare'] == 'LIKE') {
185
- $this->object->_query_args['post_title__like'] = $clause['value'];
186
- } else {
187
- $this->object->_query_args['post_title'] = $clause['value'];
188
- }
189
- break;
190
- default:
191
- // Must be metadata
192
- $clause['key'] = $clause['column'];
193
- unset($clause['column']);
194
- // Convert values to array, when required
195
- if (in_array($clause['compare'], array('IN', 'BETWEEN'))) {
196
- $clause['value'] = explode(',', $clause['value']);
197
- foreach ($clause['value'] as &$val) {
198
- if (!is_numeric($val)) {
199
- // In the _parse_where_clause() method, we
200
- // quote the strings and add slashes
201
- $val = stripslashes($val);
202
- $val = substr($val, 1, strlen($val) - 2);
203
- }
204
- }
205
- }
206
- if (!isset($this->object->_query_args['meta_query'])) {
207
- $this->object->_query_args['meta_query'] = array();
208
- }
209
- $this->object->_query_args['meta_query'][] = $clause;
210
- break;
211
- }
212
- }
213
- // If any where clauses have been added, specify how the conditions
214
- // will be conbined/joined
215
- if (isset($this->object->_query_args['meta_query'])) {
216
- $this->object->_query_args['meta_query']['relation'] = $join;
217
  }
 
218
  }
219
  /**
220
- * Destroys/deletes an entity from the database
221
- * @param object|C_DataMapper_Model $entity
222
- * @param bool $skip_trash (optional) Default = true
223
  * @return bool
224
  */
225
- function destroy($entity, $skip_trash = TRUE)
226
  {
227
- $retval = FALSE;
228
- $key = $this->object->get_primary_key_column();
229
- // Find the id of the entity
230
- if (is_object($entity) && isset($entity->{$key})) {
231
- $id = (int) $entity->{$key};
232
- } else {
233
- $id = (int) $entity;
234
- }
235
- // If we have an ID, then delete the post
236
- if (is_integer($id)) {
237
- // TODO: We assume that we can skip the trash. Is that correct?
238
- // FYI, Deletes postmeta as wells
239
- if (is_object(wp_delete_post($id, TRUE))) {
240
- $retval = TRUE;
241
- }
242
  }
243
- return $retval;
244
  }
245
  /**
246
- * Converts a post to an entity
247
- * @param \stdClass $post
248
- * @param boolean $model
249
- * @return \stdClass
250
  */
251
- function convert_post_to_entity($post, $model = FALSE)
252
  {
253
- $entity = new stdClass();
254
- // Unserialize the post_content_filtered field
255
- if (is_string($post->post_content_filtered)) {
256
- if ($post_content = $this->object->unserialize($post->post_content_filtered)) {
257
- foreach ($post_content as $key => $value) {
258
- $post->{$key} = $value;
259
- }
260
- }
261
- }
262
- // Unserialize the post content field
263
- if (is_string($post->post_content)) {
264
- if ($post_content = $this->object->unserialize($post->post_content)) {
265
- foreach ($post_content as $key => $value) {
266
- $post->{$key} = $value;
267
- }
268
- }
269
- }
270
- // Copy post fields to entity
271
- unset($post->post_content);
272
- unset($post->post_content_filtered);
273
- foreach ($post as $key => $value) {
274
- $entity->{$key} = $value;
275
- }
276
- $this->object->_convert_to_entity($entity);
277
- return $model ? $this->object->convert_to_model($entity) : $entity;
278
  }
279
  /**
280
- * Converts an entity to a post
281
- * @param object $entity
282
- * @return object
283
  */
284
- function _convert_entity_to_post($entity)
285
  {
286
- // Was a model passed instead of an entity?
287
- $post = $entity;
288
- if (!$entity instanceof stdClass) {
289
- $post = $entity->get_entity();
290
- }
291
- // Create the post content
292
- $post_content = clone $post;
293
- foreach ($this->object->_table_columns as $column) {
294
- unset($post_content->{$column});
295
- }
296
- unset($post->id_field);
297
- unset($post->post_content_filtered);
298
- unset($post->post_content);
299
- $post->post_content = $this->object->serialize($post_content);
300
- $post->post_content_filtered = $post->post_content;
301
- $post->post_type = $this->object->get_object_name();
302
- // Sometimes an entity can contain a data stored in an array or object
303
- // Those will be removed from the post, and serialized in the
304
- // post_content field
305
- foreach ($post as $key => $value) {
306
- if (in_array(strtolower(gettype($value)), array('object', 'array'))) {
307
- unset($post->{$key});
308
- }
309
- }
310
- // A post required a title
311
- if (!property_exists($post, 'post_title')) {
312
- $post->post_title = $this->object->get_post_title($post);
313
- }
314
- // A post also requires an excerpt
315
- if (!property_exists($post, 'post_excerpt')) {
316
- $post->post_excerpt = $this->object->get_post_excerpt($post);
317
- }
318
- return $post;
319
  }
320
  /**
321
- * Returns the WordPress database class
322
- * @global wpdb $wpdb
323
- * @return wpdb
324
  */
325
- function _wpdb()
326
  {
327
- global $wpdb;
328
- return $wpdb;
329
  }
330
  /**
331
- * Flush and update all postmeta for a particular post
332
- * @param int $post_id
333
  */
334
- function _flush_and_update_postmeta($post_id, $entity, $omit = array())
335
  {
336
- // We need to insert post meta data for each property
337
- // Unfortunately, that means flushing all existing postmeta
338
- // and then inserting new values. Depending on the number of
339
- // properties, this could be slow. So, we directly access the database
340
- /* @var $wpdb wpdb */
341
- global $wpdb;
342
- if (!is_array($omit)) {
343
- $omit = array($omit);
344
- }
345
- // By default, we omit creating meta values for columns in the posts table
346
- $omit = array_merge($omit, $this->object->_table_columns);
347
- // Delete the existing meta values
348
- $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE post_id = %s", $post_id));
349
- // Create query for new meta values
350
- $sql_parts = array();
351
- foreach ($entity as $key => $value) {
352
- if (in_array($key, $omit)) {
353
- continue;
354
- }
355
- if (is_array($value) or is_object($value)) {
356
- $value = $this->object->serialize($value);
357
- }
358
- $sql_parts[] = $wpdb->prepare("(%s, %s, %s)", $post_id, $key, $value);
359
  }
360
- $wpdb->query("INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) VALUES " . implode(',', $sql_parts));
361
  }
362
- /**
363
- * Saves an entity to the database
364
- * @param object $entity
365
- * @return int Post ID
366
- */
367
- function _save_entity($entity)
368
  {
369
- $post = $this->object->_convert_entity_to_post($entity);
370
- $primary_key = $this->object->get_primary_key_column();
371
- // TODO: unsilence this. Wordpress 3.9-beta2 is generating an error that should be corrected before its
372
- // final release.
373
- if ($post_id = @wp_insert_post($post)) {
374
- $new_entity = $this->object->find($post_id, TRUE);
375
- if ($new_entity) {
376
- foreach ($new_entity->get_entity() as $key => $value) {
377
- $entity->{$key} = $value;
378
- }
379
- }
380
- // Save properties as post meta
381
- $this->object->_flush_and_update_postmeta($post_id, $entity instanceof stdClass ? $entity : $entity->get_entity());
382
- $entity->{$primary_key} = $post_id;
383
- // Clean cache
384
- $this->object->_cache = array();
385
  }
386
- $entity->id_field = $primary_key;
387
- return $post_id;
388
  }
389
- /**
390
- * Determines whether the current statement is SELECT
391
- * @return boolean
392
- */
393
- function is_select_statement()
394
  {
395
- return isset($this->object->_query_args['is_select']) && $this->object->_query_args['is_select'];
396
  }
397
  /**
398
- * Determines whether the current statement is DELETE
399
- * @return bool
 
400
  */
401
- function is_delete_statement()
402
  {
403
- return isset($this->object->_query_args['is_delete']) && $this->object->_query_args['is_delete'];
404
  }
405
  /**
406
- * Starts a new DELETE statement
 
407
  */
408
- function delete()
409
  {
410
- $this->object->select();
411
- $this->object->_query_args['is_select'] = FALSE;
412
- $this->object->_query_args['is_delete'] = TRUE;
413
- return $this->object;
414
  }
415
- /**
416
- * Runs the query
417
- * @param string|bool $sql (optional) Run the specified query
418
- * @param object|bool $model (optional)
419
- * @param bool $convert_to_entities (optional) Default = true
420
- * @return array
421
- */
422
- function run_query($sql = FALSE, $model = FALSE, $convert_to_entities = TRUE)
423
  {
424
- $retval = array();
425
- $results = array();
426
- // All of our custom fields are stored as post meta, but is also stored as a serialized
427
- // value in the post_content field. Because of this, we don't need to look up and cache the
428
- // post meta values
429
- $this->object->_query_args['update_post_meta_cache'] = FALSE;
430
- $this->object->_query_args['update_post_meta_cache'] = FALSE;
431
- $this->object->_query_args['no_found_posts'] = FALSE;
432
- // Don't cache any manual SQL query
433
- if ($sql) {
434
- $this->object->_query_args['cache_results'] = FALSE;
435
- $this->object->_query_args['custom_sql'] = $sql;
436
- }
437
- // If this is a select query, then try fetching the results from cache
438
- $cache_key = md5(json_encode($this->object->_query_args));
439
- if ($this->is_select_statement() && $this->object->_use_cache) {
440
- $results = $this->object->get_from_cache($cache_key);
441
- }
442
- // Execute the query
443
- if (!$results) {
444
- $query = new WP_Query(array('datamapper' => TRUE));
445
- if (isset($this->object->debug)) {
446
- $this->object->_query_args['debug'] = TRUE;
447
- }
448
- $query->query_vars = $this->object->_query_args;
449
- add_action('pre_get_posts', array(&$this, 'set_query_args'), PHP_INT_MAX - 1, 1);
450
- $results = $query->get_posts();
451
- // Cache the result
452
- if ($this->is_select_statement()) {
453
- $this->object->cache($cache_key, $results);
454
- }
455
- remove_action('pre_get_posts', array(&$this, 'set_query_args'), PHP_INT_MAX - 1);
456
- }
457
- // Convert the result
458
- if ($convert_to_entities) {
459
- foreach ($results as $row) {
460
- $retval[] = $this->object->convert_post_to_entity($row, $model);
461
  }
462
- } else {
463
- $retval = $results;
464
  }
465
- // Ensure that we return an empty array when there are no results
466
- if (!$retval) {
467
- $retval = array();
468
- }
469
- return $retval;
470
  }
471
  /**
472
- * Ensure that the query args are set. We need to do this in case a third-party
473
- * plugin overrides our query
474
- * @param $query
 
475
  */
476
- function set_query_args($query)
477
  {
478
- if ($query->get('datamapper')) {
479
- $query->query_vars = $this->object->_query_args;
 
 
 
480
  }
481
- $filter = isset($query->query_vars['suppress_filters']) ? $query->query_vars['suppress_filters'] : FALSE;
482
- $query->query_vars['suppress_filters'] = apply_filters('wpml_suppress_filters', $filter);
483
  }
484
  /**
485
- * Fetches the last row
486
  * @param array $conditions (optional)
487
  * @param object|bool $model (optional)
488
- * @return object
489
  */
490
- function find_last($conditions = array(), $model = FALSE)
491
  {
492
- $retval = NULL;
493
- // Get row number for the last row
494
- $table_name = $this->object->_clean_column($this->object->get_table_name());
495
- $object_name = $this->object->_clean_column($this->object->get_object_name());
496
- $sql = $this->_wpdb()->prepare("SELECT COUNT(*) FROM {$table_name} WHERE post_type = %s", $object_name);
497
- $count = $this->_wpdb()->get_var($sql);
498
- $offset = $count - 1;
499
- $this->select();
500
- if ($conditions) {
501
- $this->where_and($conditions);
502
- }
503
- if ($offset) {
504
- $this->limit(1, $offset);
505
  }
506
- $results = $this->run_query();
507
- if ($results) {
508
- $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0];
509
  }
510
- return $retval;
 
 
 
 
 
 
511
  }
512
  /**
513
- * Returns the number of total records/entities that exist
514
- * @return int
 
 
 
 
 
 
 
515
  */
516
- function count()
517
  {
518
- $this->object->select($this->object->get_primary_key_column());
519
- $retval = $this->object->run_query(FALSE, FALSE, FALSE);
520
- return count($retval);
521
  }
522
  /**
523
- * Returns the title of the post. Used when post_title is not set
524
- * @param stdClass $entity
525
- * @return string
526
  */
527
- function get_post_title($entity)
528
  {
529
- return "Untitled {$this->object->get_object_name()}";
530
  }
531
  /**
532
- * Returns the excerpt of the post. Used when post_excerpt is not set
533
- * @param stdClass $entity
534
- * @return string
535
  */
536
- function get_post_excerpt($entity)
537
- {
538
- return '';
539
- }
540
- }
541
- /**
542
- * Class C_DataMapper_Driver_Base
543
- * @mixin Mixin_DataMapper_Driver_Base
544
- * @implements I_DataMapper_Driver
545
- */
546
- class C_DataMapper_Driver_Base extends C_Component
547
- {
548
- var $_object_name;
549
- var $_model_factory_method = FALSE;
550
- var $_columns = array();
551
- var $_table_columns = array();
552
- var $_serialized_columns = array();
553
- function define($object_name = FALSE, $context = FALSE)
554
  {
555
- parent::define($context);
556
- $this->add_mixin('Mixin_DataMapper_Driver_Base');
557
- $this->implement('I_DataMapper_Driver');
558
- $this->_object_name = $object_name;
559
  }
560
- function initialize()
 
 
 
 
 
 
 
 
 
 
 
 
 
561
  {
562
- parent::initialize();
563
- $this->_cache = array();
564
- if ($this->has_method('define_columns')) {
565
- $this->define_columns();
 
 
 
566
  }
567
- $this->lookup_columns();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  }
569
  /**
570
- * Gets the object name
571
- * @return string
 
 
 
 
 
 
572
  */
573
- function get_object_name()
574
  {
575
- return $this->_object_name;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
  }
577
- /**
578
- * Gets the name of the table
579
- * @global string $table_prefix
580
- * @return string
581
- */
582
- function get_table_name()
583
  {
584
- global $table_prefix;
585
- global $wpdb;
586
- $prefix = $table_prefix;
587
- if ($wpdb != null && $wpdb->prefix != null) {
588
- $prefix = $wpdb->prefix;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  }
590
- return apply_filters('ngg_datamapper_table_name', $prefix . $this->_object_name, $this->_object_name);
 
 
 
 
591
  }
592
  /**
593
- * Looks up using SQL the columns existing in the database, result is cached
 
 
 
594
  */
595
- function lookup_columns()
596
  {
597
- // Avoid doing multiple SHOW COLUMNS if we can help it
598
- $key = C_Photocrati_Transient_Manager::create_key('col_in_' . $this->get_table_name(), 'columns');
599
- $this->_table_columns = C_Photocrati_Transient_Manager::fetch($key, FALSE);
600
- if (!$this->_table_columns) {
601
- $this->object->update_columns_cache();
602
- }
603
- return $this->_table_columns;
604
- }
605
- /**
606
- * Looks up using SQL the columns existing in the database
607
- */
608
- function update_columns_cache()
609
- {
610
- $key = C_Photocrati_Transient_Manager::create_key('col_in_' . $this->get_table_name(), 'columns');
611
- global $wpdb;
612
- $this->_table_columns = array();
613
- $sql = "SHOW COLUMNS FROM `{$this->get_table_name()}`";
614
- foreach ($wpdb->get_results($sql) as $row) {
615
- $this->_table_columns[] = $row->Field;
616
  }
617
- C_Photocrati_Transient_Manager::update($key, $this->_table_columns);
 
618
  }
619
  /**
620
- * Determines whether a column is present for the table
621
- * @param string $column_name
622
  * @return bool
623
  */
624
- function has_column($column_name)
625
- {
626
- if (empty($this->object->_table_columns)) {
627
- $this->object->lookup_columns();
628
- }
629
- return array_search($column_name, $this->object->_table_columns) !== FALSE;
630
- }
631
- /**
632
- * Sets the name of the factory method used to create a model for this entity
633
- * @param string $method_name
634
- */
635
- function set_model_factory_method($method_name)
636
- {
637
- $this->_model_factory_method = $method_name;
638
- }
639
- /**
640
- * Gets the name of the factory method used to create a model for this entity
641
- */
642
- function get_model_factory_method()
643
  {
644
- return $this->_model_factory_method;
645
  }
646
  /**
647
- * Gets the name of the primary key column
648
- * @return string
649
  */
650
- function get_primary_key_column()
651
  {
652
- return $this->_primary_key_column;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
653
  }
654
- /**
655
- * Gets the class name of the driver used
656
- * @return string
657
- */
658
- function get_driver_class_name()
659
  {
660
- return get_called_class();
661
  }
662
- function cache($key, $results)
663
  {
664
- if ($this->object->_use_cache) {
665
- $this->_cache[$key] = $results;
666
- }
667
  }
668
- function get_from_cache($key, $default = NULL)
669
  {
670
- if ($this->object->_use_cache && isset($this->_cache[$key])) {
671
- return $this->_cache[$key];
672
- } else {
673
- return $default;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
  }
675
- }
676
- function flush_query_cache()
677
- {
678
- $this->_cache = array();
679
  }
680
  }
681
  /**
682
- * Provides instance methods for C_CustomTable_DataMapper_Driver
683
- * @mixin C_CustomTable_DataMapper_Driver
684
  */
685
- class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
686
  {
687
  /**
688
- * Gets the name of the primary key column
689
- * @return string
 
 
690
  */
691
- function get_primary_key_column()
692
  {
693
- return $this->object->_primary_key_column;
 
694
  }
695
  /**
696
- * Selects which fields to collect from the table.
697
- * NOTE: Not protected from SQL injection - DO NOT let your users specify DB columns
698
- * @param string $fields
699
- * @return object
700
  */
701
- function select($fields = NULL)
702
  {
703
- // Create a fresh slate
704
- $this->object->_init();
705
- if (!$fields or $fields == '*') {
706
- $fields = $this->get_table_name() . '.*';
 
 
 
707
  }
708
- $this->object->_select_clause = "SELECT {$fields}";
709
- return $this->object;
 
 
 
 
 
 
 
710
  }
711
  /**
712
- * Determines whether we're going to execute a SELECT statement
713
- * @return boolean
 
714
  */
715
- function is_select_statement()
716
  {
717
- return $this->object->_select_clause ? TRUE : FALSE;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
718
  }
719
  /**
720
- * Determines if we're going to be executing a DELETE statement
721
- * @return bool
722
  */
723
- function is_delete_statement()
724
  {
725
- return $this->object->_delete_clause ? TRUE : FALSE;
 
 
 
726
  }
727
  /**
728
- * Start a delete statement
 
 
729
  */
730
- function delete()
731
  {
732
- // Create a fresh slate
733
- $this->object->_init();
734
- $this->object->_delete_clause = "DELETE";
735
- return $this->object;
736
  }
737
  /**
738
- * Orders the results of the query
739
- * This method may be used multiple of times to order by more than column
740
- * @param $order_by
741
- * @param $direction
742
- * @return object
743
  */
744
- function order_by($order_by, $direction = 'ASC')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
745
  {
746
  // We treat the rand() function as an exception
747
  if (preg_match("/rand\\(\\s*\\)/", $order_by)) {
@@ -835,40 +807,6 @@ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
835
  }
836
  return $retval;
837
  }
838
- /**
839
- * Returns the generated SQL query to be executed
840
- * @param bool $no_entities Default = false
841
- * @return string
842
- */
843
- function get_generated_query($no_entities = FALSE)
844
- {
845
- $sql = array();
846
- if ($this->object->is_select_statement()) {
847
- $sql[] = $this->object->_select_clause;
848
- } elseif ($this->object->is_delete_statement()) {
849
- $sql[] = $this->object->_delete_clause;
850
- }
851
- $sql[] = 'FROM `' . $this->object->get_table_name() . '`';
852
- $where_clauses = array();
853
- foreach ($this->object->_where_clauses as $where) {
854
- $where_clauses[] = '(' . $where . ')';
855
- }
856
- if ($where_clauses) {
857
- $sql[] = 'WHERE ' . implode(' AND ', $where_clauses);
858
- }
859
- if ($this->object->is_select_statement()) {
860
- if ($this->object->_group_by_columns) {
861
- $sql[] = 'GROUP BY ' . implode(', ', $this->object->_group_by_columns);
862
- }
863
- if ($this->object->_order_clauses) {
864
- $sql[] = 'ORDER BY ' . implode(', ', $this->object->_order_clauses);
865
- }
866
- if ($this->object->_limit_clause) {
867
- $sql[] = $this->object->_limit_clause;
868
- }
869
- }
870
- return implode(' ', $sql);
871
- }
872
  /**
873
  * Run the query
874
  * @param string|bool $sql (optional) run the specified SQL
@@ -929,36 +867,6 @@ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
929
  }
930
  return $retval;
931
  }
932
- /**
933
- * Stores the entity
934
- * @param object $entity
935
- * @return bool|object
936
- */
937
- function _save_entity($entity)
938
- {
939
- $retval = FALSE;
940
- unset($entity->id_field);
941
- $primary_key = $this->object->get_primary_key_column();
942
- if (isset($entity->{$primary_key}) && $entity->{$primary_key} > 0) {
943
- if ($this->object->_update($entity)) {
944
- $retval = intval($entity->{$primary_key});
945
- }
946
- } else {
947
- $retval = $this->object->_create($entity);
948
- if ($retval) {
949
- $new_entity = $this->object->find($retval);
950
- foreach ($new_entity as $key => $value) {
951
- $entity->{$key} = $value;
952
- }
953
- }
954
- }
955
- $entity->id_field = $primary_key;
956
- // Clean cache
957
- if ($retval) {
958
- $this->object->_cache = array();
959
- }
960
- return $retval;
961
- }
962
  /**
963
  * Converts an entity to something suitable for inserting into a database column
964
  * @param object $entity
@@ -974,53 +882,6 @@ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
974
  }
975
  return $data;
976
  }
977
- /**
978
- * Destroys/deletes an entity
979
- * @param object|C_DataMapper_Model|int $entity
980
- * @return boolean
981
- */
982
- function destroy($entity)
983
- {
984
- $retval = FALSE;
985
- $key = $this->object->get_primary_key_column();
986
- // Find the id of the entity
987
- if (is_object($entity) && isset($entity->{$key})) {
988
- $id = (int) $entity->{$key};
989
- } else {
990
- $id = (int) $entity;
991
- }
992
- // If we have an ID, then delete the post
993
- if (is_numeric($id)) {
994
- $sql = $this->object->_wpdb()->prepare("DELETE FROM `{$this->object->get_table_name()}` WHERE {$key} = %s", $id);
995
- $retval = $this->object->_wpdb()->query($sql);
996
- }
997
- return $retval;
998
- }
999
- /**
1000
- * Creates a new record in the database
1001
- * @param object $entity
1002
- * @return boolean
1003
- */
1004
- function _create($entity)
1005
- {
1006
- $retval = FALSE;
1007
- $id = $this->object->_wpdb()->insert($this->object->get_table_name(), $this->object->_convert_to_table_data($entity));
1008
- if ($id) {
1009
- $key = $this->object->get_primary_key_column();
1010
- $retval = $entity->{$key} = intval($this->object->_wpdb()->insert_id);
1011
- }
1012
- return $retval;
1013
- }
1014
- /**
1015
- * Updates a record in the database
1016
- * @param object $entity
1017
- * @return int|bool
1018
- */
1019
- function _update($entity)
1020
- {
1021
- $key = $this->object->get_primary_key_column();
1022
- return $this->object->_wpdb()->update($this->object->get_table_name(), $this->object->_convert_to_table_data($entity), array($key => $entity->{$key}));
1023
- }
1024
  /**
1025
  * Fetches the last row
1026
  * @param array $conditions
@@ -1040,26 +901,6 @@ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
1040
  }
1041
  return $retval;
1042
  }
1043
- function _add_column($column_name, $datatype, $default_value = NULL)
1044
- {
1045
- $sql = "ALTER TABLE `{$this->get_table_name()}` ADD COLUMN `{$column_name}` {$datatype}";
1046
- if ($default_value) {
1047
- if (is_string($default_value)) {
1048
- $default_value = str_replace("'", "\\'", $default_value);
1049
- }
1050
- $sql .= " NOT NULL DEFAULT " . (is_string($default_value) ? "'{$default_value}" : "{$default_value}");
1051
- }
1052
- $return = $this->object->_wpdb()->query($sql) ? TRUE : FALSE;
1053
- $this->object->update_columns_cache();
1054
- return $return;
1055
- }
1056
- function _remove_column($column_name)
1057
- {
1058
- $sql = "ALTER TABLE `{$this->get_table_name()}` DROP COLUMN `{$column_name}`";
1059
- $return = $this->object->_wpdb()->query($sql) ? TRUE : FALSE;
1060
- $this->object->update_columns_cache();
1061
- return $return;
1062
- }
1063
  function get_column_names()
1064
  {
1065
  return array_keys($this->object->_columns);
@@ -1105,56 +946,167 @@ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
1105
  }
1106
  }
1107
  /**
1108
- * Class C_CustomTable_DataMapper_Driver
1109
- * @mixin C_CustomTable_DataMapper_Driver_Mixin
1110
  */
1111
- class C_CustomTable_DataMapper_Driver extends C_DataMapper_Driver_Base
1112
  {
1113
  /**
1114
- * The WordPress Database Connection
1115
- * @var wpdb
 
 
1116
  */
1117
- var $_where_clauses = array();
1118
- var $_order_clauses = array();
1119
- var $_group_by_columns = array();
1120
- var $_limit_clause = '';
1121
- var $_select_clause = '';
1122
- var $_delete_clause = '';
1123
- public $_use_cache = TRUE;
1124
- function define($object_name = FALSE, $context = FALSE)
1125
- {
1126
- parent::define($object_name, $context);
1127
- $this->add_mixin('C_CustomTable_DataMapper_Driver_Mixin');
1128
- $this->implement('I_CustomTable_DataMapper');
1129
- }
1130
- function initialize($object_name = FALSE)
1131
  {
1132
- parent::initialize();
1133
- if (!isset($this->_primary_key_column)) {
1134
- $this->_primary_key_column = $this->_lookup_primary_key_column();
 
1135
  }
1136
- $this->migrate();
 
1137
  }
1138
  /**
1139
- * Returns the database connection object for WordPress
1140
- * @global wpdb $wpdb
1141
- * @return wpdb
1142
  */
1143
- function _wpdb()
1144
  {
1145
- global $wpdb;
1146
- return $wpdb;
 
 
1147
  }
1148
  /**
1149
- * Looks up the primary key column for this table
 
 
1150
  */
1151
- function _lookup_primary_key_column()
1152
  {
1153
- $key = $this->_wpdb()->get_row("SHOW INDEX FROM {$this->get_table_name()} WHERE Key_name='PRIMARY'", ARRAY_A);
1154
- if (!$key) {
1155
- throw new Exception("Please specify the primary key for {$this->get_table_name()}");
 
 
 
 
 
 
 
 
 
 
 
 
1156
  }
1157
- return $key['Column_name'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1158
  }
1159
  }
1160
  /**
@@ -1193,277 +1145,512 @@ class E_InvalidEntityException extends E_NggErrorException
1193
  }
1194
  }
1195
  /**
1196
- * Provides instance methods for C_DataMapper_Driver_Base
1197
- * @mixin C_DataMapper_Driver_Base
 
1198
  */
1199
- class Mixin_DataMapper_Driver_Base extends Mixin
1200
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1201
  /**
1202
- * Used to clean column or table names in a SQL query
1203
- * @param string $val
1204
  * @return string
1205
  */
1206
- function _clean_column($val)
1207
  {
1208
- return str_replace(array(';', "'", '"', '`'), array(''), $val);
 
1209
  }
1210
  /**
1211
- * Notes that a particular columns is serialized, and should be unserialized when converted to an entity
1212
- * @param $column
1213
  */
1214
- function add_serialized_column($column)
1215
  {
1216
- $this->object->_serialized_columns[] = $column;
1217
  }
1218
- function unserialize_columns($object)
 
 
 
 
 
 
1219
  {
1220
- foreach ($this->object->_serialized_columns as $column) {
1221
- if (isset($object->{$column}) && is_string($object->{$column})) {
1222
- $object->{$column} = C_NextGen_Serializable::unserialize($object->{$column});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1223
  }
 
1224
  }
 
1225
  }
1226
  /**
1227
- * Serializes the data
1228
- *
1229
- * @param mixed $value
1230
- * @return string
1231
  */
1232
- function serialize($value)
1233
  {
1234
- return C_NextGen_Serializable::serialize($value);
 
 
 
 
 
1235
  }
1236
  /**
1237
- * Unserializes data using our proprietary format
1238
- *
1239
- * @param string $value
1240
- * @return mixed
1241
  */
1242
- function unserialize($value)
1243
  {
1244
- return C_NextGen_Serializable::unserialize($value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1245
  }
1246
  /**
1247
- * Finds a partiular entry by id
1248
- * @param int|stdClass|C_DataMapper_Model $entity
1249
- * @param object|bool $model (optional)
1250
- * @return null|object
1251
  */
1252
- function find($entity, $model = FALSE)
1253
  {
1254
- $retval = NULL;
1255
- // Get primary key of the entity
1256
- $pkey = $this->object->get_primary_key_column();
1257
- if (!is_numeric($entity)) {
1258
- $entity = isset($entity->{$pkey}) ? intval($entity->{$pkey}) : FALSE;
 
 
 
1259
  }
1260
- // If we have an entity ID, then get the record
1261
- if ($entity) {
1262
- $results = $this->object->select()->where_and(array("{$pkey} = %d", $entity))->limit(1, 0)->run_query();
1263
- if ($results) {
1264
- $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0];
 
1265
  }
1266
  }
1267
- return $retval;
 
 
 
 
 
 
 
1268
  }
1269
  /**
1270
- * Fetches the first row
1271
- * @param array $conditions (optional)
1272
- * @param object|bool $model (optional)
1273
- * @return null|object
1274
  */
1275
- function find_first($conditions = array(), $model = FALSE)
1276
  {
1277
- $results = $this->object->select()->where_and($conditions)->limit(1, 0)->run_query();
1278
- if ($results) {
1279
- return $model ? $this->object->convert_to_model($results[0]) : $results[0];
1280
- } else {
1281
- return NULL;
1282
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1283
  }
1284
  /**
1285
- * Queries all rows
1286
- * @param array $conditions (optional)
1287
- * @param object|bool $model (optional)
1288
- * @return array
1289
  */
1290
- function find_all($conditions = array(), $model = FALSE)
1291
  {
1292
- // Sometimes users will forget that the first parameter is conditions, and think it's $model instead
1293
- if ($conditions === TRUE) {
1294
- $conditions = array();
1295
- $model = TRUE;
1296
- }
1297
- if ($conditions === FALSE) {
1298
- $conditions = array();
 
1299
  }
1300
- $results = $this->object->select()->where_and($conditions)->run_query();
1301
- if ($results && $model) {
1302
- foreach ($results as &$r) {
1303
- $r = $this->object->convert_to_model($r);
 
 
 
 
 
 
 
 
1304
  }
 
1305
  }
1306
- return $results;
1307
  }
1308
  /**
1309
- * Filters the query using conditions:
1310
- * E.g.
1311
- * array("post_title = %s", "Foo")
1312
- * array(
1313
- * array("post_title = %s", "Foo"),
1314
- *
1315
- * )
1316
- * @param array $conditions (optional)
1317
- * @return self
1318
  */
1319
- function where_and($conditions = array())
1320
  {
1321
- return $this->object->_where($conditions, 'AND');
1322
  }
1323
  /**
1324
- * @param array $conditions (optional)
1325
- * @return self
1326
  */
1327
- function where_or($conditions = array())
1328
  {
1329
- return $this->object->where($conditions, 'OR');
1330
  }
1331
  /**
1332
- * @param array $conditions (optional)
1333
- * @return self
1334
- */
1335
- function where($conditions = array())
1336
- {
1337
- return $this->object->_where($conditions, 'AND');
1338
- }
1339
- /** Parses the where clauses
1340
- * They could look like the following:
1341
- *
1342
- * array(
1343
- * "post_id = 1"
1344
- * array("post_id = %d", 1),
1345
- * )
1346
- *
1347
- * or simply "post_id = 1"
1348
- * @param array|string $conditions
1349
- * @param string $operator
1350
- * @return ExtensibleObject
1351
  */
1352
- function _where($conditions = array(), $operator)
1353
  {
1354
- $where_clauses = array();
1355
- // If conditions is not an array, make it one
1356
- if (!is_array($conditions)) {
1357
- $conditions = array($conditions);
1358
- } elseif (!empty($conditions) && !is_array($conditions[0])) {
1359
- // Just a single condition was passed, but with a bind
1360
- $conditions = array($conditions);
 
 
 
 
 
1361
  }
1362
- // Iterate through each condition
1363
- foreach ($conditions as $condition) {
1364
- if (is_string($condition)) {
1365
- $clause = $this->object->_parse_where_clause($condition);
1366
- if ($clause) {
1367
- $where_clauses[] = $clause;
1368
- }
1369
- } else {
1370
- $clause = array_shift($condition);
1371
- $clause = $this->object->_parse_where_clause($clause, $condition);
1372
- if ($clause) {
1373
- $where_clauses[] = $clause;
1374
- }
 
 
 
 
 
 
 
 
 
 
 
1375
  }
 
 
1376
  }
1377
- // Add where clause to query
1378
- if ($where_clauses) {
1379
- $this->object->_add_where_clause($where_clauses, $operator);
1380
  }
1381
- return $this->object;
1382
  }
1383
  /**
1384
- * Parses a where clause and returns an associative array
1385
- * representing the query
1386
- *
1387
- * E.g. parse_where_clause("post_title = %s", "Foo Bar")
1388
- *
1389
- * @global wpdb $wpdb
1390
- * @param string $condition
1391
- * @return array
1392
  */
1393
- function _parse_where_clause($condition)
1394
  {
1395
- $column = '';
1396
- $operator = '';
1397
- $value = '';
1398
- $numeric = TRUE;
1399
- // Substitute any placeholders
1400
- global $wpdb;
1401
- $binds = func_get_args();
1402
- $binds = isset($binds[1]) ? $binds[1] : array();
1403
- // first argument is the condition
1404
- foreach ($binds as &$bind) {
1405
- // A bind could be an array, used for the 'IN' operator
1406
- // or a simple scalar value. We need to convert arrays
1407
- // into scalar values
1408
- if (is_object($bind)) {
1409
- $bind = (array) $bind;
1410
- }
1411
- if (is_array($bind) && !empty($bind)) {
1412
- foreach ($bind as &$val) {
1413
- if (!is_numeric($val)) {
1414
- $val = '"' . addslashes($val) . '"';
1415
- $numeric = FALSE;
1416
- }
1417
- }
1418
- $bind = implode(',', $bind);
1419
- } else {
1420
- if (is_array($bind) && empty($bind)) {
1421
- $bind = 'NULL';
1422
- } else {
1423
- if (!is_numeric($bind)) {
1424
- $numeric = FALSE;
1425
- }
1426
- }
1427
- }
1428
- }
1429
- if ($binds) {
1430
- $condition = $wpdb->prepare($condition, $binds);
1431
- }
1432
- // Parse the where clause
1433
- if (preg_match("/^[^\\s]+/", $condition, $match)) {
1434
- $column = trim(array_shift($match));
1435
- $condition = str_replace($column, '', $condition);
1436
  }
1437
- if (preg_match("/(NOT )?IN|(NOT )?LIKE|(NOT )?BETWEEN|[=!<>]+/i", $condition, $match)) {
1438
- $operator = trim(array_shift($match));
1439
- $condition = str_replace($operator, '', $condition);
1440
- $operator = strtolower($operator);
1441
- $value = trim($condition);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1442
  }
1443
- // Values will automatically be quoted, so remove them
1444
- // If the value is part of an IN clause or BETWEEN clause and
1445
- // has multiple values, we attempt to split the values apart into an
1446
- // array and iterate over them individually
1447
- if ($operator == 'in') {
1448
- $values = preg_split("/'?\\s?(,)\\s?'?/i", $value);
1449
- } elseif ($operator == 'between') {
1450
- $values = preg_split("/'?\\s?(AND)\\s?'?/i", $value);
1451
  }
1452
- // If there's a single value, treat it as an array so that we
1453
- // can still iterate
1454
- if (empty($values)) {
1455
- $values = array($value);
1456
  }
1457
- foreach ($values as $index => $value) {
1458
- $value = preg_replace("/^(\\()?'/", '', $value);
1459
- $value = preg_replace("/'(\\))?\$/", '', $value);
1460
- $values[$index] = $value;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1461
  }
1462
- if (count($values) > 1) {
1463
- $value = $values;
 
 
 
 
1464
  }
1465
- // Return the WP Query meta query parameters
1466
- $retval = array('column' => $column, 'value' => $value, 'compare' => strtoupper($operator), 'type' => $numeric ? 'numeric' : 'string');
1467
  return $retval;
1468
  }
1469
  /**
@@ -1489,56 +1676,6 @@ class Mixin_DataMapper_Driver_Base extends Mixin
1489
  }
1490
  return $stdObject;
1491
  }
1492
- function strip_slashes($stdObject_or_array_or_string)
1493
- {
1494
- /**
1495
- * Some objects have properties that are recursive objects. To avoid this we have to keep track
1496
- * of what objects we've already processed when we're running this method recursively
1497
- */
1498
- static $level = 0;
1499
- static $processed_objects = array();
1500
- $level++;
1501
- $processed_objects[] = $stdObject_or_array_or_string;
1502
- if (is_string($stdObject_or_array_or_string)) {
1503
- $stdObject_or_array_or_string = str_replace("\\'", "'", str_replace('\\"', '"', str_replace("\\\\", "\\", $stdObject_or_array_or_string)));
1504
- } elseif (is_object($stdObject_or_array_or_string) && !in_array($stdObject_or_array_or_string, $processed_objects)) {
1505
- foreach (get_object_vars($stdObject_or_array_or_string) as $key => $val) {
1506
- if ($val != $stdObject_or_array_or_string && $key != '_mapper') {
1507
- $stdObject_or_array_or_string->{$key} = $this->strip_slashes($val);
1508
- }
1509
- }
1510
- $processed_objects[] = $stdObject_or_array_or_string;
1511
- } elseif (is_array($stdObject_or_array_or_string)) {
1512
- foreach ($stdObject_or_array_or_string as $key => $val) {
1513
- if ($key != '_mixins') {
1514
- $stdObject_or_array_or_string[$key] = $this->strip_slashes($val);
1515
- }
1516
- }
1517
- }
1518
- $level--;
1519
- if ($level == 0) {
1520
- $processed_objects = array();
1521
- }
1522
- return $stdObject_or_array_or_string;
1523
- }
1524
- /**
1525
- * Converts a stdObject entity to a model
1526
- * @param object $stdObject
1527
- * @param string|bool $context (optional)
1528
- * @return object
1529
- */
1530
- function convert_to_model($stdObject, $context = FALSE)
1531
- {
1532
- // Create a factory
1533
- $retval = NULL;
1534
- try {
1535
- $this->object->_convert_to_entity($stdObject);
1536
- } catch (Exception $ex) {
1537
- throw new E_InvalidEntityException($ex);
1538
- }
1539
- $retval = $this->object->create($stdObject, $context);
1540
- return $retval;
1541
- }
1542
  /**
1543
  * Creates a new model
1544
  * @param object|array $properties (optional)
@@ -1557,15 +1694,6 @@ class Mixin_DataMapper_Driver_Base extends Mixin
1557
  }
1558
  return $factory->create($this->object->get_model_factory_method(), $entity, $this->object, $context);
1559
  }
1560
- /**
1561
- * Determines whether an object is actually a model
1562
- * @param mixed $obj
1563
- * @return bool
1564
- */
1565
- function is_model($obj)
1566
- {
1567
- return is_subclass_of($obj, 'C_DataMapper_Model') or get_class($obj) == 'C_DataMapper_Model';
1568
- }
1569
  /**
1570
  * Saves an entity
1571
  * @param stdClass|C_DataMapper_Model $entity
@@ -1627,138 +1755,10 @@ class Mixin_DataMapper_Driver_Base extends Mixin
1627
  {
1628
  return isset($entity->__defaults_set) && $entity->__defaults_set == TRUE;
1629
  }
1630
- /**
1631
- * If a field has no value, then use the default value.
1632
- * @param stdClass|C_DataMapper_Model $object
1633
- */
1634
- function _set_default_value($object)
1635
- {
1636
- $array = NULL;
1637
- $field = NULL;
1638
- $default_value = NULL;
1639
- // The first argument MUST be an object
1640
- if (!is_object($object)) {
1641
- throw new E_InvalidEntityException();
1642
- }
1643
- // This method has two signatures:
1644
- // 1) _set_default_value($object, $field, $default_value)
1645
- // 2) _set_default_value($object, $array_field, $field, $default_value)
1646
- // Handle #1
1647
- $args = func_get_args();
1648
- if (count($args) == 4) {
1649
- list($object, $array, $field, $default_value) = $args;
1650
- if (!isset($object->{$array})) {
1651
- $object->{$array} = array();
1652
- $object->{$array}[$field] = NULL;
1653
- } else {
1654
- $arr =& $object->{$array};
1655
- if (!isset($arr[$field])) {
1656
- $arr[$field] = NULL;
1657
- }
1658
- }
1659
- $array =& $object->{$array};
1660
- $value =& $array[$field];
1661
- if ($value === '' or is_null($value)) {
1662
- $value = $default_value;
1663
- }
1664
- } else {
1665
- list($object, $field, $default_value) = $args;
1666
- if (!isset($object->{$field})) {
1667
- $object->{$field} = NULL;
1668
- }
1669
- $value = $object->{$field};
1670
- if ($value === '' or is_null($value)) {
1671
- $object->{$field} = $default_value;
1672
- }
1673
- }
1674
- }
1675
  function define_column($name, $type, $default_value = NULL)
1676
  {
1677
  $this->object->_columns[$name] = array('type' => $type, 'default_value' => $default_value);
1678
  }
1679
- function get_defined_column_names()
1680
- {
1681
- return array_keys($this->object->_columns);
1682
- }
1683
- function has_defined_column($name)
1684
- {
1685
- $columns = $this->object->_columns;
1686
- return isset($columns[$name]);
1687
- }
1688
- function cast_columns($entity)
1689
- {
1690
- foreach ($this->object->_columns as $key => $properties) {
1691
- $value = property_exists($entity, $key) ? $entity->{$key} : NULL;
1692
- $default_value = $properties['default_value'];
1693
- if (!is_null($value) && $value !== $default_value) {
1694
- $column_type = $this->object->_columns[$key]['type'];
1695
- if (preg_match("/varchar|text/i", $column_type)) {
1696
- if (!is_array($value) && !is_object($value)) {
1697
- $entity->{$key} = strval($value);
1698
- }
1699
- } else {
1700
- if (preg_match("/decimal|numeric|double|float/i", $column_type)) {
1701
- $entity->{$key} = floatval($value);
1702
- } else {
1703
- if (preg_match("/int/i", $column_type)) {
1704
- $entity->{$key} = intval($value);
1705
- } else {
1706
- if (preg_match("/bool/i", $column_type)) {
1707
- $entity->{$key} = $value ? TRUE : FALSE;
1708
- }
1709
- }
1710
- }
1711
- }
1712
- } else {
1713
- $entity->{$key} = $default_value;
1714
- }
1715
- }
1716
- return $entity;
1717
- }
1718
- }
1719
- /**
1720
- * Class C_CustomPost_DataMapper_Driver
1721
- * @mixin Mixin_CustomPost_DataMapper_Driver
1722
- * @implements I_CustomPost_DataMapper
1723
- */
1724
- class C_CustomPost_DataMapper_Driver extends C_DataMapper_Driver_Base
1725
- {
1726
- var $_query_args = array();
1727
- var $_primary_key_column = 'ID';
1728
- static $_post_table_columns = array();
1729
- public $_use_cache = TRUE;
1730
- function define($object_name = FALSE, $context = FALSE)
1731
- {
1732
- if (strlen($object_name) > 20) {
1733
- throw new Exception("The custom post name can be no longer than 20 characters long");
1734
- }
1735
- parent::define($object_name, $context);
1736
- $this->add_mixin('Mixin_CustomPost_DataMapper_Driver');
1737
- $this->implement('I_CustomPost_DataMapper');
1738
- }
1739
- function lookup_columns()
1740
- {
1741
- if (empty(self::$_post_table_columns)) {
1742
- $columns = parent::lookup_columns();
1743
- foreach ($columns as $column) {
1744
- self::$_post_table_columns[] = $column;
1745
- }
1746
- } else {
1747
- foreach (self::$_post_table_columns as $column) {
1748
- $this->_table_columns[] = $column;
1749
- }
1750
- }
1751
- }
1752
- /**
1753
- * Gets the name of the table
1754
- * @global string $table_prefix
1755
- * @return string
1756
- */
1757
- function get_table_name()
1758
- {
1759
- global $table_prefix;
1760
- return $table_prefix . 'posts';
1761
- }
1762
  }
1763
  /**
1764
  * Class C_DataMapper_Model
24
  }
25
  }
26
  /**
27
+ * Class C_DataMapper_Driver_Base
28
+ * @mixin Mixin_DataMapper_Driver_Base
29
+ * @implements I_DataMapper_Driver
30
  */
31
+ class C_DataMapper_Driver_Base extends C_Component
32
  {
33
+ var $_object_name;
34
+ var $_model_factory_method = FALSE;
35
+ var $_columns = array();
36
+ var $_table_columns = array();
37
+ var $_serialized_columns = array();
38
+ function define($object_name = FALSE, $context = FALSE)
39
  {
40
+ parent::define($context);
41
+ $this->add_mixin('Mixin_DataMapper_Driver_Base');
42
+ $this->implement('I_DataMapper_Driver');
43
+ $this->_object_name = $object_name;
44
  }
45
+ function initialize()
 
 
 
 
 
 
46
  {
47
+ parent::initialize();
48
+ $this->_cache = array();
49
+ if ($this->has_method('define_columns')) {
50
+ $this->define_columns();
51
+ }
52
+ $this->lookup_columns();
53
  }
54
  /**
55
+ * Gets the object name
56
+ * @return string
 
 
57
  */
58
+ function get_object_name()
59
  {
60
+ return $this->_object_name;
 
 
 
 
 
 
 
 
 
 
61
  }
62
  /**
63
+ * Gets the name of the table
64
+ * @global string $table_prefix
65
+ * @return string
 
66
  */
67
+ function get_table_name()
68
  {
69
+ global $table_prefix;
70
+ global $wpdb;
71
+ $prefix = $table_prefix;
72
+ if ($wpdb != null && $wpdb->prefix != null) {
73
+ $prefix = $wpdb->prefix;
 
 
 
74
  }
75
+ return apply_filters('ngg_datamapper_table_name', $prefix . $this->_object_name, $this->_object_name);
76
  }
77
  /**
78
+ * Looks up using SQL the columns existing in the database, result is cached
 
 
79
  */
80
+ function lookup_columns()
81
  {
82
+ // Avoid doing multiple SHOW COLUMNS if we can help it
83
+ $key = C_Photocrati_Transient_Manager::create_key('col_in_' . $this->get_table_name(), 'columns');
84
+ $this->_table_columns = C_Photocrati_Transient_Manager::fetch($key, FALSE);
85
+ if (!$this->_table_columns) {
86
+ $this->object->update_columns_cache();
87
  }
88
+ return $this->_table_columns;
89
  }
90
  /**
91
+ * Looks up using SQL the columns existing in the database
 
 
92
  */
93
+ function update_columns_cache()
94
  {
95
+ $key = C_Photocrati_Transient_Manager::create_key('col_in_' . $this->get_table_name(), 'columns');
96
+ global $wpdb;
97
+ $this->_table_columns = array();
98
+ $sql = "SHOW COLUMNS FROM `{$this->get_table_name()}`";
99
+ foreach ($wpdb->get_results($sql) as $row) {
100
+ $this->_table_columns[] = $row->Field;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
102
+ C_Photocrati_Transient_Manager::update($key, $this->_table_columns);
103
  }
104
  /**
105
+ * Determines whether a column is present for the table
106
+ * @param string $column_name
 
107
  * @return bool
108
  */
109
+ function has_column($column_name)
110
  {
111
+ if (empty($this->object->_table_columns)) {
112
+ $this->object->lookup_columns();
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
+ return array_search($column_name, $this->object->_table_columns) !== FALSE;
115
  }
116
  /**
117
+ * Sets the name of the factory method used to create a model for this entity
118
+ * @param string $method_name
 
 
119
  */
120
+ function set_model_factory_method($method_name)
121
  {
122
+ $this->_model_factory_method = $method_name;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  }
124
  /**
125
+ * Gets the name of the factory method used to create a model for this entity
 
 
126
  */
127
+ function get_model_factory_method()
128
  {
129
+ return $this->_model_factory_method;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
131
  /**
132
+ * Gets the name of the primary key column
133
+ * @return string
 
134
  */
135
+ function get_primary_key_column()
136
  {
137
+ return $this->_primary_key_column;
 
138
  }
139
  /**
140
+ * Gets the class name of the driver used
141
+ * @return string
142
  */
143
+ function get_driver_class_name()
144
  {
145
+ return get_called_class();
146
+ }
147
+ function cache($key, $results)
148
+ {
149
+ if ($this->object->_use_cache) {
150
+ $this->_cache[$key] = $results;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  }
 
152
  }
153
+ function get_from_cache($key, $default = NULL)
 
 
 
 
 
154
  {
155
+ if ($this->object->_use_cache && isset($this->_cache[$key])) {
156
+ return $this->_cache[$key];
157
+ } else {
158
+ return $default;
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
 
 
160
  }
161
+ function flush_query_cache()
 
 
 
 
162
  {
163
+ $this->_cache = array();
164
  }
165
  /**
166
+ * Used to clean column or table names in a SQL query
167
+ * @param string $val
168
+ * @return string
169
  */
170
+ function _clean_column($val)
171
  {
172
+ return str_replace(array(';', "'", '"', '`'), array(''), $val);
173
  }
174
  /**
175
+ * Notes that a particular columns is serialized, and should be unserialized when converted to an entity
176
+ * @param $column
177
  */
178
+ function add_serialized_column($column)
179
  {
180
+ $this->object->_serialized_columns[] = $column;
 
 
 
181
  }
182
+ function unserialize_columns($object)
 
 
 
 
 
 
 
183
  {
184
+ foreach ($this->object->_serialized_columns as $column) {
185
+ if (isset($object->{$column}) && is_string($object->{$column})) {
186
+ $object->{$column} = C_NextGen_Serializable::unserialize($object->{$column});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  }
 
 
188
  }
 
 
 
 
 
189
  }
190
  /**
191
+ * Fetches the first row
192
+ * @param array $conditions (optional)
193
+ * @param object|bool $model (optional)
194
+ * @return null|object
195
  */
196
+ function find_first($conditions = array(), $model = FALSE)
197
  {
198
+ $results = $this->object->select()->where_and($conditions)->limit(1, 0)->run_query();
199
+ if ($results) {
200
+ return $model ? $this->object->convert_to_model($results[0]) : $results[0];
201
+ } else {
202
+ return NULL;
203
  }
 
 
204
  }
205
  /**
206
+ * Queries all rows
207
  * @param array $conditions (optional)
208
  * @param object|bool $model (optional)
209
+ * @return array
210
  */
211
+ function find_all($conditions = array(), $model = FALSE)
212
  {
213
+ // Sometimes users will forget that the first parameter is conditions, and think it's $model instead
214
+ if ($conditions === TRUE) {
215
+ $conditions = array();
216
+ $model = TRUE;
 
 
 
 
 
 
 
 
 
217
  }
218
+ if ($conditions === FALSE) {
219
+ $conditions = array();
 
220
  }
221
+ $results = $this->object->select()->where_and($conditions)->run_query();
222
+ if ($results && $model) {
223
+ foreach ($results as &$r) {
224
+ $r = $this->object->convert_to_model($r);
225
+ }
226
+ }
227
+ return $results;
228
  }
229
  /**
230
+ * Filters the query using conditions:
231
+ * E.g.
232
+ * array("post_title = %s", "Foo")
233
+ * array(
234
+ * array("post_title = %s", "Foo"),
235
+ *
236
+ * )
237
+ * @param array $conditions (optional)
238
+ * @return self
239
  */
240
+ function where_and($conditions = array())
241
  {
242
+ return $this->object->_where($conditions, 'AND');
 
 
243
  }
244
  /**
245
+ * @param array $conditions (optional)
246
+ * @return self
 
247
  */
248
+ function where_or($conditions = array())
249
  {
250
+ return $this->object->where($conditions, 'OR');
251
  }
252
  /**
253
+ * @param array $conditions (optional)
254
+ * @return self
 
255
  */
256
+ function where($conditions = array())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  {
258
+ return $this->object->_where($conditions, 'AND');
 
 
 
259
  }
260
+ /** Parses the where clauses
261
+ * They could look like the following:
262
+ *
263
+ * array(
264
+ * "post_id = 1"
265
+ * array("post_id = %d", 1),
266
+ * )
267
+ *
268
+ * or simply "post_id = 1"
269
+ * @param array|string $conditions
270
+ * @param string $operator
271
+ * @return ExtensibleObject
272
+ */
273
+ function _where($conditions = array(), $operator)
274
  {
275
+ $where_clauses = array();
276
+ // If conditions is not an array, make it one
277
+ if (!is_array($conditions)) {
278
+ $conditions = array($conditions);
279
+ } elseif (!empty($conditions) && !is_array($conditions[0])) {
280
+ // Just a single condition was passed, but with a bind
281
+ $conditions = array($conditions);
282
  }
283
+ // Iterate through each condition
284
+ foreach ($conditions as $condition) {
285
+ if (is_string($condition)) {
286
+ $clause = $this->object->_parse_where_clause($condition);
287
+ if ($clause) {
288
+ $where_clauses[] = $clause;
289
+ }
290
+ } else {
291
+ $clause = array_shift($condition);
292
+ $clause = $this->object->_parse_where_clause($clause, $condition);
293
+ if ($clause) {
294
+ $where_clauses[] = $clause;
295
+ }
296
+ }
297
+ }
298
+ // Add where clause to query
299
+ if ($where_clauses) {
300
+ $this->object->_add_where_clause($where_clauses, $operator);
301
+ }
302
+ return $this->object;
303
  }
304
  /**
305
+ * Parses a where clause and returns an associative array
306
+ * representing the query
307
+ *
308
+ * E.g. parse_where_clause("post_title = %s", "Foo Bar")
309
+ *
310
+ * @global wpdb $wpdb
311
+ * @param string $condition
312
+ * @return array
313
  */
314
+ function _parse_where_clause($condition)
315
  {
316
+ $column = '';
317
+ $operator = '';
318
+ $value = '';
319
+ $numeric = TRUE;
320
+ // Substitute any placeholders
321
+ global $wpdb;
322
+ $binds = func_get_args();
323
+ $binds = isset($binds[1]) ? $binds[1] : array();
324
+ // first argument is the condition
325
+ foreach ($binds as &$bind) {
326
+ // A bind could be an array, used for the 'IN' operator
327
+ // or a simple scalar value. We need to convert arrays
328
+ // into scalar values
329
+ if (is_object($bind)) {
330
+ $bind = (array) $bind;
331
+ }
332
+ if (is_array($bind) && !empty($bind)) {
333
+ foreach ($bind as &$val) {
334
+ if (!is_numeric($val)) {
335
+ $val = '"' . addslashes($val) . '"';
336
+ $numeric = FALSE;
337
+ }
338
+ }
339
+ $bind = implode(',', $bind);
340
+ } else {
341
+ if (is_array($bind) && empty($bind)) {
342
+ $bind = 'NULL';
343
+ } else {
344
+ if (!is_numeric($bind)) {
345
+ $numeric = FALSE;
346
+ }
347
+ }
348
+ }
349
+ }
350
+ if ($binds) {
351
+ $condition = $wpdb->prepare($condition, $binds);
352
+ }
353
+ // Parse the where clause
354
+ if (preg_match("/^[^\\s]+/", $condition, $match)) {
355
+ $column = trim(array_shift($match));
356
+ $condition = str_replace($column, '', $condition);
357
+ }
358
+ if (preg_match("/(NOT )?IN|(NOT )?LIKE|(NOT )?BETWEEN|[=!<>]+/i", $condition, $match)) {
359
+ $operator = trim(array_shift($match));
360
+ $condition = str_replace($operator, '', $condition);
361
+ $operator = strtolower($operator);
362
+ $value = trim($condition);
363
+ }
364
+ // Values will automatically be quoted, so remove them
365
+ // If the value is part of an IN clause or BETWEEN clause and
366
+ // has multiple values, we attempt to split the values apart into an
367
+ // array and iterate over them individually
368
+ if ($operator == 'in') {
369
+ $values = preg_split("/'?\\s?(,)\\s?'?/i", $value);
370
+ } elseif ($operator == 'between') {
371
+ $values = preg_split("/'?\\s?(AND)\\s?'?/i", $value);
372
+ }
373
+ // If there's a single value, treat it as an array so that we
374
+ // can still iterate
375
+ if (empty($values)) {
376
+ $values = array($value);
377
+ }
378
+ foreach ($values as $index => $value) {
379
+ $value = preg_replace("/^(\\()?'/", '', $value);
380
+ $value = preg_replace("/'(\\))?\$/", '', $value);
381
+ $values[$index] = $value;
382
+ }
383
+ if (count($values) > 1) {
384
+ $value = $values;
385
+ }
386
+ // Return the WP Query meta query parameters
387
+ $retval = array('column' => $column, 'value' => $value, 'compare' => strtoupper($operator), 'type' => $numeric ? 'numeric' : 'string');
388
+ return $retval;
389
  }
390
+ function strip_slashes($stdObject_or_array_or_string)
 
 
 
 
 
391
  {
392
+ /**
393
+ * Some objects have properties that are recursive objects. To avoid this we have to keep track
394
+ * of what objects we've already processed when we're running this method recursively
395
+ */
396
+ static $level = 0;
397
+ static $processed_objects = array();
398
+ $level++;
399
+ $processed_objects[] = $stdObject_or_array_or_string;
400
+ if (is_string($stdObject_or_array_or_string)) {
401
+ $stdObject_or_array_or_string = str_replace("\\'", "'", str_replace('\\"', '"', str_replace("\\\\", "\\", $stdObject_or_array_or_string)));
402
+ } elseif (is_object($stdObject_or_array_or_string) && !in_array($stdObject_or_array_or_string, $processed_objects)) {
403
+ foreach (get_object_vars($stdObject_or_array_or_string) as $key => $val) {
404
+ if ($val != $stdObject_or_array_or_string && $key != '_mapper') {
405
+ $stdObject_or_array_or_string->{$key} = $this->strip_slashes($val);
406
+ }
407
+ }
408
+ $processed_objects[] = $stdObject_or_array_or_string;
409
+ } elseif (is_array($stdObject_or_array_or_string)) {
410
+ foreach ($stdObject_or_array_or_string as $key => $val) {
411
+ if ($key != '_mixins') {
412
+ $stdObject_or_array_or_string[$key] = $this->strip_slashes($val);
413
+ }
414
+ }
415
  }
416
+ $level--;
417
+ if ($level == 0) {
418
+ $processed_objects = array();
419
+ }
420
+ return $stdObject_or_array_or_string;
421
  }
422
  /**
423
+ * Converts a stdObject entity to a model
424
+ * @param object $stdObject
425
+ * @param string|bool $context (optional)
426
+ * @return object
427
  */
428
+ function convert_to_model($stdObject, $context = FALSE)
429
  {
430
+ // Create a factory
431
+ $retval = NULL;
432
+ try {
433
+ $this->object->_convert_to_entity($stdObject);
434
+ } catch (Exception $ex) {
435
+ throw new E_InvalidEntityException($ex);
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
437
+ $retval = $this->object->create($stdObject, $context);
438
+ return $retval;
439
  }
440
  /**
441
+ * Determines whether an object is actually a model
442
+ * @param mixed $obj
443
  * @return bool
444
  */
445
+ function is_model($obj)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  {
447
+ return is_subclass_of($obj, 'C_DataMapper_Model') or get_class($obj) == 'C_DataMapper_Model';
448
  }
449
  /**
450
+ * If a field has no value, then use the default value.
451
+ * @param stdClass|C_DataMapper_Model $object
452
  */
453
+ function _set_default_value($object)
454
  {
455
+ $array = NULL;
456
+ $field = NULL;
457
+ $default_value = NULL;
458
+ // The first argument MUST be an object
459
+ if (!is_object($object)) {
460
+ throw new E_InvalidEntityException();
461
+ }
462
+ // This method has two signatures:
463
+ // 1) _set_default_value($object, $field, $default_value)
464
+ // 2) _set_default_value($object, $array_field, $field, $default_value)
465
+ // Handle #1
466
+ $args = func_get_args();
467
+ if (count($args) == 4) {
468
+ list($object, $array, $field, $default_value) = $args;
469
+ if (!isset($object->{$array})) {
470
+ $object->{$array} = array();
471
+ $object->{$array}[$field] = NULL;
472
+ } else {
473
+ $arr =& $object->{$array};
474
+ if (!isset($arr[$field])) {
475
+ $arr[$field] = NULL;
476
+ }
477
+ }
478
+ $array =& $object->{$array};
479
+ $value =& $array[$field];
480
+ if ($value === '' or is_null($value)) {
481
+ $value = $default_value;
482
+ }
483
+ } else {
484
+ list($object, $field, $default_value) = $args;
485
+ if (!isset($object->{$field})) {
486
+ $object->{$field} = NULL;
487
+ }
488
+ $value = $object->{$field};
489
+ if ($value === '' or is_null($value)) {
490
+ $object->{$field} = $default_value;
491
+ }
492
+ }
493
  }
494
+ function get_defined_column_names()
 
 
 
 
495
  {
496
+ return array_keys($this->object->_columns);
497
  }
498
+ function has_defined_column($name)
499
  {
500
+ $columns = $this->object->_columns;
501
+ return isset($columns[$name]);
 
502
  }
503
+ function cast_columns($entity)
504
  {
505
+ foreach ($this->object->_columns as $key => $properties) {
506
+ $value = property_exists($entity, $key) ? $entity->{$key} : NULL;
507
+ $default_value = $properties['default_value'];
508
+ if (!is_null($value) && $value !== $default_value) {
509
+ $column_type = $this->object->_columns[$key]['type'];
510
+ if (preg_match("/varchar|text/i", $column_type)) {
511
+ if (!is_array($value) && !is_object($value)) {
512
+ $entity->{$key} = strval($value);
513
+ }
514
+ } else {
515
+ if (preg_match("/decimal|numeric|double|float/i", $column_type)) {
516
+ $entity->{$key} = floatval($value);
517
+ } else {
518
+ if (preg_match("/int/i", $column_type)) {
519
+ $entity->{$key} = intval($value);
520
+ } else {
521
+ if (preg_match("/bool/i", $column_type)) {
522
+ $entity->{$key} = $value ? TRUE : FALSE;
523
+ }
524
+ }
525
+ }
526
+ }
527
+ } else {
528
+ $entity->{$key} = $default_value;
529
+ }
530
  }
531
+ return $entity;
 
 
 
532
  }
533
  }
534
  /**
535
+ * Provides instance methods for C_CustomPost_DataMapper_Driver
536
+ * @mixin C_CustomPost_DataMapper_Driver
537
  */
538
+ class Mixin_CustomPost_DataMapper_Driver extends Mixin
539
  {
540
  /**
541
+ * Used to select which fields should be returned. NOT currently used by
542
+ * this implementation of the datamapper driver
543
+ * @param string $fields
544
+ * @return C_DataMapper_Driver_Base
545
  */
546
+ function select($fields = '*')
547
  {
548
+ $this->object->_query_args = array('post_type' => $this->object->get_object_name(), 'paged' => FALSE, 'fields' => $fields, 'post_status' => 'any', 'datamapper' => TRUE, 'posts_per_page' => -1, 'is_select' => TRUE, 'is_delete' => FALSE);
549
+ return $this->object;
550
  }
551
  /**
552
+ * Destroys/deletes an entity from the database
553
+ * @param object|C_DataMapper_Model $entity
554
+ * @param bool $skip_trash (optional) Default = true
555
+ * @return bool
556
  */
557
+ function destroy($entity, $skip_trash = TRUE)
558
  {
559
+ $retval = FALSE;
560
+ $key = $this->object->get_primary_key_column();
561
+ // Find the id of the entity
562
+ if (is_object($entity) && isset($entity->{$key})) {
563
+ $id = (int) $entity->{$key};
564
+ } else {
565
+ $id = (int) $entity;
566
  }
567
+ // If we have an ID, then delete the post
568
+ if (is_integer($id)) {
569
+ // TODO: We assume that we can skip the trash. Is that correct?
570
+ // FYI, Deletes postmeta as wells
571
+ if (is_object(wp_delete_post($id, TRUE))) {
572
+ $retval = TRUE;
573
+ }
574
+ }
575
+ return $retval;
576
  }
577
  /**
578
+ * Saves an entity to the database
579
+ * @param object $entity
580
+ * @return int Post ID
581
  */
582
+ function _save_entity($entity)
583
  {
584
+ $post = $this->object->_convert_entity_to_post($entity);
585
+ $primary_key = $this->object->get_primary_key_column();
586
+ // TODO: unsilence this. Wordpress 3.9-beta2 is generating an error that should be corrected before its
587
+ // final release.
588
+ if ($post_id = @wp_insert_post($post)) {
589
+ $new_entity = $this->object->find($post_id, TRUE);
590
+ if ($new_entity) {
591
+ foreach ($new_entity->get_entity() as $key => $value) {
592
+ $entity->{$key} = $value;
593
+ }
594
+ }
595
+ // Save properties as post meta
596
+ $this->object->_flush_and_update_postmeta($post_id, $entity instanceof stdClass ? $entity : $entity->get_entity());
597
+ $entity->{$primary_key} = $post_id;
598
+ // Clean cache
599
+ $this->object->_cache = array();
600
+ }
601
+ $entity->id_field = $primary_key;
602
+ return $post_id;
603
  }
604
  /**
605
+ * Starts a new DELETE statement
 
606
  */
607
+ function delete()
608
  {
609
+ $this->object->select();
610
+ $this->object->_query_args['is_select'] = FALSE;
611
+ $this->object->_query_args['is_delete'] = TRUE;
612
+ return $this->object;
613
  }
614
  /**
615
+ * Returns the title of the post. Used when post_title is not set
616
+ * @param stdClass $entity
617
+ * @return string
618
  */
619
+ function get_post_title($entity)
620
  {
621
+ return "Untitled {$this->object->get_object_name()}";
 
 
 
622
  }
623
  /**
624
+ * Returns the excerpt of the post. Used when post_excerpt is not set
625
+ * @param stdClass $entity
626
+ * @return string
 
 
627
  */
628
+ function get_post_excerpt($entity)
629
+ {
630
+ return '';
631
+ }
632
+ }
633
+ /**
634
+ * Class C_CustomTable_DataMapper_Driver
635
+ * @mixin C_CustomTable_DataMapper_Driver_Mixin
636
+ */
637
+ class C_CustomTable_DataMapper_Driver extends C_DataMapper_Driver_Base
638
+ {
639
+ /**
640
+ * The WordPress Database Connection
641
+ * @var wpdb
642
+ */
643
+ var $_where_clauses = array();
644
+ var $_order_clauses = array();
645
+ var $_group_by_columns = array();
646
+ var $_limit_clause = '';
647
+ var $_select_clause = '';
648
+ var $_delete_clause = '';
649
+ public $_use_cache = TRUE;
650
+ function define($object_name = FALSE, $context = FALSE)
651
+ {
652
+ parent::define($object_name, $context);
653
+ $this->add_mixin('C_CustomTable_DataMapper_Driver_Mixin');
654
+ $this->implement('I_CustomTable_DataMapper');
655
+ }
656
+ function initialize($object_name = FALSE)
657
+ {
658
+ parent::initialize();
659
+ if (!isset($this->_primary_key_column)) {
660
+ $this->_primary_key_column = $this->_lookup_primary_key_column();
661
+ }
662
+ $this->migrate();
663
+ }
664
+ /**
665
+ * Returns the database connection object for WordPress
666
+ * @global wpdb $wpdb
667
+ * @return wpdb
668
+ */
669
+ function _wpdb()
670
+ {
671
+ global $wpdb;
672
+ return $wpdb;
673
+ }
674
+ /**
675
+ * Looks up the primary key column for this table
676
+ */
677
+ function _lookup_primary_key_column()
678
+ {
679
+ $key = $this->_wpdb()->get_row("SHOW INDEX FROM {$this->get_table_name()} WHERE Key_name='PRIMARY'", ARRAY_A);
680
+ if (!$key) {
681
+ throw new Exception("Please specify the primary key for {$this->get_table_name()}");
682
+ }
683
+ return $key['Column_name'];
684
+ }
685
+ /**
686
+ * Gets the name of the primary key column
687
+ * @return string
688
+ */
689
+ function get_primary_key_column()
690
+ {
691
+ return $this->object->_primary_key_column;
692
+ }
693
+ /**
694
+ * Determines whether we're going to execute a SELECT statement
695
+ * @return boolean
696
+ */
697
+ function is_select_statement()
698
+ {
699
+ return $this->object->_select_clause ? TRUE : FALSE;
700
+ }
701
+ /**
702
+ * Determines if we're going to be executing a DELETE statement
703
+ * @return bool
704
+ */
705
+ function is_delete_statement()
706
+ {
707
+ return $this->object->_delete_clause ? TRUE : FALSE;
708
+ }
709
+ /**
710
+ * Orders the results of the query
711
+ * This method may be used multiple of times to order by more than column
712
+ * @param $order_by
713
+ * @param $direction
714
+ * @return object
715
+ */
716
+ function order_by($order_by, $direction = 'ASC')
717
  {
718
  // We treat the rand() function as an exception
719
  if (preg_match("/rand\\(\\s*\\)/", $order_by)) {
807
  }
808
  return $retval;
809
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
810
  /**
811
  * Run the query
812
  * @param string|bool $sql (optional) run the specified SQL
867
  }
868
  return $retval;
869
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
870
  /**
871
  * Converts an entity to something suitable for inserting into a database column
872
  * @param object $entity
882
  }
883
  return $data;
884
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
885
  /**
886
  * Fetches the last row
887
  * @param array $conditions
901
  }
902
  return $retval;
903
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
904
  function get_column_names()
905
  {
906
  return array_keys($this->object->_columns);
946
  }
947
  }
948
  /**
949
+ * Provides instance methods for C_CustomTable_DataMapper_Driver
950
+ * @mixin C_CustomTable_DataMapper_Driver
951
  */
952
+ class C_CustomTable_DataMapper_Driver_Mixin extends Mixin
953
  {
954
  /**
955
+ * Selects which fields to collect from the table.
956
+ * NOTE: Not protected from SQL injection - DO NOT let your users specify DB columns
957
+ * @param string $fields
958
+ * @return object
959
  */
960
+ function select($fields = NULL)
 
 
 
 
 
 
 
 
 
 
 
 
 
961
  {
962
+ // Create a fresh slate
963
+ $this->object->_init();
964
+ if (!$fields or $fields == '*') {
965
+ $fields = $this->get_table_name() . '.*';
966
  }
967
+ $this->object->_select_clause = "SELECT {$fields}";
968
+ return $this->object;
969
  }
970
  /**
971
+ * Start a delete statement
 
 
972
  */
973
+ function delete()
974
  {
975
+ // Create a fresh slate
976
+ $this->object->_init();
977
+ $this->object->_delete_clause = "DELETE";
978
+ return $this->object;
979
  }
980
  /**
981
+ * Stores the entity
982
+ * @param object $entity
983
+ * @return bool|object
984
  */
985
+ function _save_entity($entity)
986
  {
987
+ $retval = FALSE;
988
+ unset($entity->id_field);
989
+ $primary_key = $this->object->get_primary_key_column();
990
+ if (isset($entity->{$primary_key}) && $entity->{$primary_key} > 0) {
991
+ if ($this->object->_update($entity)) {
992
+ $retval = intval($entity->{$primary_key});
993
+ }
994
+ } else {
995
+ $retval = $this->object->_create($entity);
996
+ if ($retval) {
997
+ $new_entity = $this->object->find($retval);
998
+ foreach ($new_entity as $key => $value) {
999
+ $entity->{$key} = $value;
1000
+ }
1001
+ }
1002
  }
1003
+ $entity->id_field = $primary_key;
1004
+ // Clean cache
1005
+ if ($retval) {
1006
+ $this->object->_cache = array();
1007
+ }
1008
+ return $retval;
1009
+ }
1010
+ /**
1011
+ * Destroys/deletes an entity
1012
+ * @param object|C_DataMapper_Model|int $entity
1013
+ * @return boolean
1014
+ */
1015
+ function destroy($entity)
1016
+ {
1017
+ $retval = FALSE;
1018
+ $key = $this->object->get_primary_key_column();
1019
+ // Find the id of the entity
1020
+ if (is_object($entity) && isset($entity->{$key})) {
1021
+ $id = (int) $entity->{$key};
1022
+ } else {
1023
+ $id = (int) $entity;
1024
+ }
1025
+ // If we have an ID, then delete the post
1026
+ if (is_numeric($id)) {
1027
+ $sql = $this->object->_wpdb()->prepare("DELETE FROM `{$this->object->get_table_name()}` WHERE {$key} = %s", $id);
1028
+ $retval = $this->object->_wpdb()->query($sql);
1029
+ }
1030
+ return $retval;
1031
+ }
1032
+ /**
1033
+ * Creates a new record in the database
1034
+ * @param object $entity
1035
+ * @return boolean
1036
+ */
1037
+ function _create($entity)
1038
+ {
1039
+ $retval = FALSE;
1040
+ $id = $this->object->_wpdb()->insert($this->object->get_table_name(), $this->object->_convert_to_table_data($entity));
1041
+ if ($id) {
1042
+ $key = $this->object->get_primary_key_column();
1043
+ $retval = $entity->{$key} = intval($this->object->_wpdb()->insert_id);
1044
+ }
1045
+ return $retval;
1046
+ }
1047
+ /**
1048
+ * Updates a record in the database
1049
+ * @param object $entity
1050
+ * @return int|bool
1051
+ */
1052
+ function _update($entity)
1053
+ {
1054
+ $key = $this->object->get_primary_key_column();
1055
+ return $this->object->_wpdb()->update($this->object->get_table_name(), $this->object->_convert_to_table_data($entity), array($key => $entity->{$key}));
1056
+ }
1057
+ function _add_column($column_name, $datatype, $default_value = NULL)
1058
+ {
1059
+ $sql = "ALTER TABLE `{$this->get_table_name()}` ADD COLUMN `{$column_name}` {$datatype}";
1060
+ if ($default_value) {
1061
+ if (is_string($default_value)) {
1062
+ $default_value = str_replace("'", "\\'", $default_value);
1063
+ }
1064
+ $sql .= " NOT NULL DEFAULT " . (is_string($default_value) ? "'{$default_value}" : "{$default_value}");
1065
+ }
1066
+ $return = $this->object->_wpdb()->query($sql) ? TRUE : FALSE;
1067
+ $this->object->update_columns_cache();
1068
+ return $return;
1069
+ }
1070
+ function _remove_column($column_name)
1071
+ {
1072
+ $sql = "ALTER TABLE `{$this->get_table_name()}` DROP COLUMN `{$column_name}`";
1073
+ $return = $this->object->_wpdb()->query($sql) ? TRUE : FALSE;
1074
+ $this->object->update_columns_cache();
1075
+ return $return;
1076
+ }
1077
+ /**
1078
+ * Returns the generated SQL query to be executed
1079
+ * @param bool $no_entities Default = false
1080
+ * @return string
1081
+ */
1082
+ function get_generated_query($no_entities = FALSE)
1083
+ {
1084
+ $sql = array();
1085
+ if ($this->object->is_select_statement()) {
1086
+ $sql[] = $this->object->_select_clause;
1087
+ } elseif ($this->object->is_delete_statement()) {
1088
+ $sql[] = $this->object->_delete_clause;
1089
+ }
1090
+ $sql[] = 'FROM `' . $this->object->get_table_name() . '`';
1091
+ $where_clauses = array();
1092
+ foreach ($this->object->_where_clauses as $where) {
1093
+ $where_clauses[] = '(' . $where . ')';
1094
+ }
1095
+ if ($where_clauses) {
1096
+ $sql[] = 'WHERE ' . implode(' AND ', $where_clauses);
1097
+ }
1098
+ if ($this->object->is_select_statement()) {
1099
+ if ($this->object->_group_by_columns) {
1100
+ $sql[] = 'GROUP BY ' . implode(', ', $this->object->_group_by_columns);
1101
+ }
1102
+ if ($this->object->_order_clauses) {
1103
+ $sql[] = 'ORDER BY ' . implode(', ', $this->object->_order_clauses);
1104
+ }
1105
+ if ($this->object->_limit_clause) {
1106
+ $sql[] = $this->object->_limit_clause;
1107
+ }
1108
+ }
1109
+ return implode(' ', $sql);
1110
  }
1111
  }
1112
  /**
1145
  }
1146
  }
1147
  /**
1148
+ * Class C_CustomPost_DataMapper_Driver
1149
+ * @mixin Mixin_CustomPost_DataMapper_Driver
1150
+ * @implements I_CustomPost_DataMapper
1151
  */
1152
+ class C_CustomPost_DataMapper_Driver extends C_DataMapper_Driver_Base
1153
  {
1154
+ var $_query_args = array();
1155
+ var $_primary_key_column = 'ID';
1156
+ static $_post_table_columns = array();
1157
+ public $_use_cache = TRUE;
1158
+ function define($object_name = FALSE, $context = FALSE)
1159
+ {
1160
+ if (strlen($object_name) > 20) {
1161
+ throw new Exception("The custom post name can be no longer than 20 characters long");
1162
+ }
1163
+ parent::define($object_name, $context);
1164
+ $this->add_mixin('Mixin_CustomPost_DataMapper_Driver');
1165
+ $this->implement('I_CustomPost_DataMapper');
1166
+ }
1167
+ function lookup_columns()
1168
+ {
1169
+ if (empty(self::$_post_table_columns)) {
1170
+ $columns = parent::lookup_columns();
1171
+ foreach ($columns as $column) {
1172
+ self::$_post_table_columns[] = $column;
1173
+ }
1174
+ } else {
1175
+ foreach (self::$_post_table_columns as $column) {
1176
+ $this->_table_columns[] = $column;
1177
+ }
1178
+ }
1179
+ }
1180
  /**
1181
+ * Gets the name of the table
1182
+ * @global string $table_prefix
1183
  * @return string
1184
  */
1185
+ function get_table_name()
1186
  {
1187
+ global $table_prefix;
1188
+ return $table_prefix . 'posts';
1189
  }
1190
  /**
1191
+ * Returns a list of querable table columns for posts
1192
+ * @return array
1193
  */
1194
+ function _get_querable_table_columns()
1195
  {
1196
+ return array('name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count');
1197
  }
1198
+ /**
1199
+ * Specifies an order clause
1200
+ * @param string $order_by
1201
+ * @param string $direction
1202
+ * @return C_DataMapper_Driver_Base
1203
+ */
1204
+ function order_by($order_by, $direction = 'ASC')
1205
  {
1206
+ // Make an exception for the rand() method
1207
+ $order_by = preg_replace("/rand\\(\\s*\\)/", 'rand', $order_by);
1208
+ if (in_array($order_by, $this->object->_get_querable_table_columns())) {
1209
+ $this->object->_query_args['orderby'] = $order_by;
1210
+ } else {
1211
+ // ordering by a meta value
1212
+ $this->object->_query_args['orderby'] = 'meta_value';
1213
+ $this->object->_query_args['meta_key'] = $order_by;
1214
+ }
1215
+ $this->object->_query_args['order'] = $direction;
1216
+ return $this->object;
1217
+ }
1218
+ /**
1219
+ * Specifies a limit and optional offset
1220
+ * @param int $max
1221
+ * @param int|bool $offset (optional)
1222
+ * @return object
1223
+ */
1224
+ function limit($max, $offset = FALSE)
1225
+ {
1226
+ if ($max) {
1227
+ $this->object->_query_args['paged'] = TRUE;
1228
+ if ($offset) {
1229
+ $this->object->_query_args['offset'] = $offset;
1230
+ } else {
1231
+ unset($this->object->_query_args['offset']);
1232
  }
1233
+ $this->object->_query_args['posts_per_page'] = $max;
1234
  }
1235
+ return $this->object;
1236
  }
1237
  /**
1238
+ * Specifies a list of columns to group by
1239
+ * @param array|string $columns
1240
+ * @return object
 
1241
  */
1242
+ function group_by($columns = array())
1243
  {
1244
+ if (!isset($this->object->_query_args['group_by_columns'])) {
1245
+ $this->object->_query_args['group_by_columns'] = $columns;
1246
+ } else {
1247
+ $this->object->_query_args['group_by_columns'] = array_merge($this->object->_query_args['group_by_columns'], $columns);
1248
+ }
1249
+ return $this->object;
1250
  }
1251
  /**
1252
+ * Adds a WP_Query where clause
1253
+ * @param array $where_clauses
1254
+ * @param string $join
 
1255
  */
1256
+ function _add_where_clause($where_clauses, $join)
1257
  {
1258
+ foreach ($where_clauses as $clause) {
1259
+ // $clause => array(
1260
+ // 'column' => 'ID',
1261
+ // 'value' => 1210,
1262
+ // 'compare' => '='
1263
+ // )
1264
+ // Determine where what the where clause is comparing
1265
+ switch ($clause['column']) {
1266
+ case 'author':
1267
+ case 'author_id':
1268
+ $this->object->_query_args['author'] = $clause['value'];
1269
+ break;
1270
+ case 'author_name':
1271
+ $this->object->_query_args['author_name'] = $clause['value'];
1272
+ break;
1273
+ case 'cat':
1274
+ case 'cat_id':
1275
+ case 'category_id':
1276
+ switch ($clause['compare']) {
1277
+ case '=':
1278
+ case 'BETWEEN':
1279
+ case 'IN':
1280
+ if (!isset($this->object->_query_args['category__in'])) {
1281
+ $this->object->_query_args['category__in'] = array();
1282
+ }
1283
+ $this->object->_query_args['category__in'][] = $clause['value'];
1284
+ break;
1285
+ case '!=':
1286
+ case 'NOT BETWEEN':
1287
+ case 'NOT IN':
1288
+ if (!isset($this->object->_query_args['category__not_in'])) {
1289
+ $this->object->_query_args['category__not_in'] = array();
1290
+ }
1291
+ $this->object->_query_args['category__not_in'][] = $clause['value'];
1292
+ break;
1293
+ }
1294
+ break;
1295
+ case 'category_name':
1296
+ $this->object->_query_args['category_name'] = $clause['value'];
1297
+ break;
1298
+ case 'post_id':
1299
+ case $this->object->get_primary_key_column():
1300
+ switch ($clause['compare']) {
1301
+ case '=':
1302
+ case 'IN':
1303
+ case 'BETWEEN':
1304
+ if (!isset($this->object->_query_args['post__in'])) {
1305
+ $this->object->_query_args['post__in'] = array();
1306
+ }
1307
+ $this->object->_query_args['post__in'][] = $clause['value'];
1308
+ break;
1309
+ default:
1310
+ if (!isset($this->object->_query_args['post__not_in'])) {
1311
+ $this->object->_query_args['post__not_in'] = array();
1312
+ }
1313
+ $this->object->_query_args['post__not_in'][] = $clause['value'];
1314
+ break;
1315
+ }
1316
+ break;
1317
+ case 'pagename':
1318
+ case 'postname':
1319
+ case 'page_name':
1320
+ case 'post_name':
1321
+ if ($clause['compare'] == 'LIKE') {
1322
+ $this->object->_query_args['page_name__like'] = $clause['value'];
1323
+ } elseif ($clause['compare'] == '=') {
1324
+ $this->object->_query_args['pagename'] = $clause['value'];
1325
+ } elseif ($clause['compare'] == 'IN') {
1326
+ $this->object->_query_args['page_name__in'] = $clause['value'];
1327
+ }
1328
+ break;
1329
+ case 'post_title':
1330
+ // Post title uses custom WHERE clause
1331
+ if ($clause['compare'] == 'LIKE') {
1332
+ $this->object->_query_args['post_title__like'] = $clause['value'];
1333
+ } else {
1334
+ $this->object->_query_args['post_title'] = $clause['value'];
1335
+ }
1336
+ break;
1337
+ default:
1338
+ // Must be metadata
1339
+ $clause['key'] = $clause['column'];
1340
+ unset($clause['column']);
1341
+ // Convert values to array, when required
1342
+ if (in_array($clause['compare'], array('IN', 'BETWEEN'))) {
1343
+ $clause['value'] = explode(',', $clause['value']);
1344
+ foreach ($clause['value'] as &$val) {
1345
+ if (!is_numeric($val)) {
1346
+ // In the _parse_where_clause() method, we
1347
+ // quote the strings and add slashes
1348
+ $val = stripslashes($val);
1349
+ $val = substr($val, 1, strlen($val) - 2);
1350
+ }
1351
+ }
1352
+ }
1353
+ if (!isset($this->object->_query_args['meta_query'])) {
1354
+ $this->object->_query_args['meta_query'] = array();
1355
+ }
1356
+ $this->object->_query_args['meta_query'][] = $clause;
1357
+ break;
1358
+ }
1359
+ }
1360
+ // If any where clauses have been added, specify how the conditions
1361
+ // will be conbined/joined
1362
+ if (isset($this->object->_query_args['meta_query'])) {
1363
+ $this->object->_query_args['meta_query']['relation'] = $join;
1364
+ }
1365
  }
1366
  /**
1367
+ * Converts a post to an entity
1368
+ * @param \stdClass $post
1369
+ * @param boolean $model
1370
+ * @return \stdClass
1371
  */
1372
+ function convert_post_to_entity($post, $model = FALSE)
1373
  {
1374
+ $entity = new stdClass();
1375
+ // Unserialize the post_content_filtered field
1376
+ if (is_string($post->post_content_filtered)) {
1377
+ if ($post_content = $this->object->unserialize($post->post_content_filtered)) {
1378
+ foreach ($post_content as $key => $value) {
1379
+ $post->{$key} = $value;
1380
+ }
1381
+ }
1382
  }
1383
+ // Unserialize the post content field
1384
+ if (is_string($post->post_content)) {
1385
+ if ($post_content = $this->object->unserialize($post->post_content)) {
1386
+ foreach ($post_content as $key => $value) {
1387
+ $post->{$key} = $value;
1388
+ }
1389
  }
1390
  }
1391
+ // Copy post fields to entity
1392
+ unset($post->post_content);
1393
+ unset($post->post_content_filtered);
1394
+ foreach ($post as $key => $value) {
1395
+ $entity->{$key} = $value;
1396
+ }
1397
+ $this->object->_convert_to_entity($entity);
1398
+ return $model ? $this->object->convert_to_model($entity) : $entity;
1399
  }
1400
  /**
1401
+ * Converts an entity to a post
1402
+ * @param object $entity
1403
+ * @return object
 
1404
  */
1405
+ function _convert_entity_to_post($entity)
1406
  {
1407
+ // Was a model passed instead of an entity?
1408
+ $post = $entity;
1409
+ if (!$entity instanceof stdClass) {
1410
+ $post = $entity->get_entity();
 
1411
  }
1412
+ // Create the post content
1413
+ $post_content = clone $post;
1414
+ foreach ($this->object->_table_columns as $column) {
1415
+ unset($post_content->{$column});
1416
+ }
1417
+ unset($post->id_field);
1418
+ unset($post->post_content_filtered);
1419
+ unset($post->post_content);
1420
+ $post->post_content = $this->object->serialize($post_content);
1421
+ $post->post_content_filtered = $post->post_content;
1422
+ $post->post_type = $this->object->get_object_name();
1423
+ // Sometimes an entity can contain a data stored in an array or object
1424
+ // Those will be removed from the post, and serialized in the
1425
+ // post_content field
1426
+ foreach ($post as $key => $value) {
1427
+ if (in_array(strtolower(gettype($value)), array('object', 'array'))) {
1428
+ unset($post->{$key});
1429
+ }
1430
+ }
1431
+ // A post required a title
1432
+ if (!property_exists($post, 'post_title')) {
1433
+ $post->post_title = $this->object->get_post_title($post);
1434
+ }
1435
+ // A post also requires an excerpt
1436
+ if (!property_exists($post, 'post_excerpt')) {
1437
+ $post->post_excerpt = $this->object->get_post_excerpt($post);
1438
+ }
1439
+ return $post;
1440
+ }
1441
+ /**
1442
+ * Returns the WordPress database class
1443
+ * @global wpdb $wpdb
1444
+ * @return wpdb
1445
+ */
1446
+ function _wpdb()
1447
+ {
1448
+ global $wpdb;
1449
+ return $wpdb;
1450
  }
1451
  /**
1452
+ * Flush and update all postmeta for a particular post
1453
+ * @param int $post_id
 
 
1454
  */
1455
+ function _flush_and_update_postmeta($post_id, $entity, $omit = array())
1456
  {
1457
+ // We need to insert post meta data for each property
1458
+ // Unfortunately, that means flushing all existing postmeta
1459
+ // and then inserting new values. Depending on the number of
1460
+ // properties, this could be slow. So, we directly access the database
1461
+ /* @var $wpdb wpdb */
1462
+ global $wpdb;
1463
+ if (!is_array($omit)) {
1464
+ $omit = array($omit);
1465
  }
1466
+ // By default, we omit creating meta values for columns in the posts table
1467
+ $omit = array_merge($omit, $this->object->_table_columns);
1468
+ // Delete the existing meta values
1469
+ $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->postmeta} WHERE post_id = %s", $post_id));
1470
+ // Create query for new meta values
1471
+ $sql_parts = array();
1472
+ foreach ($entity as $key => $value) {
1473
+ if (in_array($key, $omit)) {
1474
+ continue;
1475
+ }
1476
+ if (is_array($value) or is_object($value)) {
1477
+ $value = $this->object->serialize($value);
1478
  }
1479
+ $sql_parts[] = $wpdb->prepare("(%s, %s, %s)", $post_id, $key, $value);
1480
  }
1481
+ $wpdb->query("INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) VALUES " . implode(',', $sql_parts));
1482
  }
1483
  /**
1484
+ * Determines whether the current statement is SELECT
1485
+ * @return boolean
 
 
 
 
 
 
 
1486
  */
1487
+ function is_select_statement()
1488
  {
1489
+ return isset($this->object->_query_args['is_select']) && $this->object->_query_args['is_select'];
1490
  }
1491
  /**
1492
+ * Determines whether the current statement is DELETE
1493
+ * @return bool
1494
  */
1495
+ function is_delete_statement()
1496
  {
1497
+ return isset($this->object->_query_args['is_delete']) && $this->object->_query_args['is_delete'];
1498
  }
1499
  /**
1500
+ * Runs the query
1501
+ * @param string|bool $sql (optional) Run the specified query
1502
+ * @param object|bool $model (optional)
1503
+ * @param bool $convert_to_entities (optional) Default = true
1504
+ * @return array
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1505
  */
1506
+ function run_query($sql = FALSE, $model = FALSE, $convert_to_entities = TRUE)
1507
  {
1508
+ $retval = array();
1509
+ $results = array();
1510
+ // All of our custom fields are stored as post meta, but is also stored as a serialized
1511
+ // value in the post_content field. Because of this, we don't need to look up and cache the
1512
+ // post meta values
1513
+ $this->object->_query_args['update_post_meta_cache'] = FALSE;
1514
+ $this->object->_query_args['update_post_meta_cache'] = FALSE;
1515
+ $this->object->_query_args['no_found_posts'] = FALSE;
1516
+ // Don't cache any manual SQL query
1517
+ if ($sql) {
1518
+ $this->object->_query_args['cache_results'] = FALSE;
1519
+ $this->object->_query_args['custom_sql'] = $sql;
1520
  }
1521
+ // If this is a select query, then try fetching the results from cache
1522
+ $cache_key = md5(json_encode($this->object->_query_args));
1523
+ if ($this->is_select_statement() && $this->object->_use_cache) {
1524
+ $results = $this->object->get_from_cache($cache_key);
1525
+ }
1526
+ // Execute the query
1527
+ if (!$results) {
1528
+ $query = new WP_Query(array('datamapper' => TRUE));
1529
+ if (isset($this->object->debug)) {
1530
+ $this->object->_query_args['debug'] = TRUE;
1531
+ }
1532
+ $query->query_vars = $this->object->_query_args;
1533
+ add_action('pre_get_posts', array(&$this, 'set_query_args'), PHP_INT_MAX - 1, 1);
1534
+ $results = $query->get_posts();
1535
+ // Cache the result
1536
+ if ($this->is_select_statement()) {
1537
+ $this->object->cache($cache_key, $results);
1538
+ }
1539
+ remove_action('pre_get_posts', array(&$this, 'set_query_args'), PHP_INT_MAX - 1);
1540
+ }
1541
+ // Convert the result
1542
+ if ($convert_to_entities) {
1543
+ foreach ($results as $row) {
1544
+ $retval[] = $this->object->convert_post_to_entity($row, $model);
1545
  }
1546
+ } else {
1547
+ $retval = $results;
1548
  }
1549
+ // Ensure that we return an empty array when there are no results
1550
+ if (!$retval) {
1551
+ $retval = array();
1552
  }
1553
+ return $retval;
1554
  }
1555
  /**
1556
+ * Ensure that the query args are set. We need to do this in case a third-party
1557
+ * plugin overrides our query
1558
+ * @param $query
 
 
 
 
 
1559
  */
1560
+ function set_query_args($query)
1561
  {
1562
+ if ($query->get('datamapper')) {
1563
+ $query->query_vars = $this->object->_query_args;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1564
  }
1565
+ $filter = isset($query->query_vars['suppress_filters']) ? $query->query_vars['suppress_filters'] : FALSE;
1566
+ $query->query_vars['suppress_filters'] = apply_filters('wpml_suppress_filters', $filter);
1567
+ }
1568
+ /**
1569
+ * Fetches the last row
1570
+ * @param array $conditions (optional)
1571
+ * @param object|bool $model (optional)
1572
+ * @return object
1573
+ */
1574
+ function find_last($conditions = array(), $model = FALSE)
1575
+ {
1576
+ $retval = NULL;
1577
+ // Get row number for the last row
1578
+ $table_name = $this->object->_clean_column($this->object->get_table_name());
1579
+ $object_name = $this->object->_clean_column($this->object->get_object_name());
1580
+ $sql = $this->_wpdb()->prepare("SELECT COUNT(*) FROM {$table_name} WHERE post_type = %s", $object_name);
1581
+ $count = $this->_wpdb()->get_var($sql);
1582
+ $offset = $count - 1;
1583
+ $this->select();
1584
+ if ($conditions) {
1585
+ $this->where_and($conditions);
1586
  }
1587
+ if ($offset) {
1588
+ $this->limit(1, $offset);
 
 
 
 
 
 
1589
  }
1590
+ $results = $this->run_query();
1591
+ if ($results) {
1592
+ $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0];
 
1593
  }
1594
+ return $retval;
1595
+ }
1596
+ /**
1597
+ * Returns the number of total records/entities that exist
1598
+ * @return int
1599
+ */
1600
+ function count()
1601
+ {
1602
+ $this->object->select($this->object->get_primary_key_column());
1603
+ $retval = $this->object->run_query(FALSE, FALSE, FALSE);
1604
+ return count($retval);
1605
+ }
1606
+ }
1607
+ /**
1608
+ * Provides instance methods for C_DataMapper_Driver_Base
1609
+ * @mixin C_DataMapper_Driver_Base
1610
+ */
1611
+ class Mixin_DataMapper_Driver_Base extends Mixin
1612
+ {
1613
+ /**
1614
+ * Serializes the data
1615
+ *
1616
+ * @param mixed $value
1617
+ * @return string
1618
+ */
1619
+ function serialize($value)
1620
+ {
1621
+ return C_NextGen_Serializable::serialize($value);
1622
+ }
1623
+ /**
1624
+ * Unserializes data using our proprietary format
1625
+ *
1626
+ * @param string $value
1627
+ * @return mixed
1628
+ */
1629
+ function unserialize($value)
1630
+ {
1631
+ return C_NextGen_Serializable::unserialize($value);
1632
+ }
1633
+ /**
1634
+ * Finds a partiular entry by id
1635
+ * @param int|stdClass|C_DataMapper_Model $entity
1636
+ * @param object|bool $model (optional)
1637
+ * @return null|object
1638
+ */
1639
+ function find($entity, $model = FALSE)
1640
+ {
1641
+ $retval = NULL;
1642
+ // Get primary key of the entity
1643
+ $pkey = $this->object->get_primary_key_column();
1644
+ if (!is_numeric($entity)) {
1645
+ $entity = isset($entity->{$pkey}) ? intval($entity->{$pkey}) : FALSE;
1646
  }
1647
+ // If we have an entity ID, then get the record
1648
+ if ($entity) {
1649
+ $results = $this->object->select()->where_and(array("{$pkey} = %d", $entity))->limit(1, 0)->run_query();
1650
+ if ($results) {
1651
+ $retval = $model ? $this->object->convert_to_model($results[0]) : $results[0];
1652
+ }
1653
  }
 
 
1654
  return $retval;
1655
  }
1656
  /**
1676
  }
1677
  return $stdObject;
1678
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1679
  /**
1680
  * Creates a new model
1681
  * @param object|array $properties (optional)
1694
  }
1695
  return $factory->create($this->object->get_model_factory_method(), $entity, $this->object, $context);
1696
  }
 
 
 
 
 
 
 
 
 
1697
  /**
1698
  * Saves an entity
1699
  * @param stdClass|C_DataMapper_Model $entity
1755
  {
1756
  return isset($entity->__defaults_set) && $entity->__defaults_set == TRUE;
1757
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1758
  function define_column($name, $type, $default_value = NULL)
1759
  {
1760
  $this->object->_columns[$name] = array('type' => $type, 'default_value' => $default_value);
1761
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1762
  }
1763
  /**
1764
  * Class C_DataMapper_Model
products/photocrati_nextgen/modules/fs/package.module.fs.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  * Class C_Fs
4
- * @mixin Mixin_Fs_Instance_Methods
5
  * @implements I_Fs
6
  */
7
  class C_Fs extends C_Component
@@ -28,7 +28,6 @@ class C_Fs extends C_Component
28
  function define($context = FALSE)
29
  {
30
  parent::define($context);
31
- $this->add_mixin('Mixin_Fs_Instance_Methods');
32
  $this->implement('I_Fs');
33
  }
34
  function initialize()
@@ -36,9 +35,84 @@ class C_Fs extends C_Component
36
  parent::initialize();
37
  $this->_document_root = $this->set_document_root(ABSPATH);
38
  }
39
- }
40
- class Mixin_Fs_Instance_Methods extends Mixin
41
- {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  function add_trailing_slash($path)
43
  {
44
  return rtrim($path, "/\\") . DIRECTORY_SEPARATOR;
@@ -258,82 +332,4 @@ class Mixin_Fs_Instance_Methods extends Mixin
258
  }
259
  return array($path, $module);
260
  }
261
- /**
262
- * Gets the document root for this application
263
- * @param string $type Must be one of plugins, plugins_mu, templates, styles, content, gallery, or root
264
- * @return string
265
- */
266
- function get_document_root($type = 'root')
267
- {
268
- $retval = NULL;
269
- switch ($type) {
270
- case 'plugins':
271
- case 'plugin':
272
- $retval = WP_PLUGIN_DIR;
273
- break;
274
- case 'plugins_mu':
275
- case 'plugin_mu':
276
- $retval = WPMU_PLUGIN_DIR;
277
- break;
278
- case 'templates':
279
- case 'template':
280
- case 'themes':
281
- case 'theme':
282
- $retval = get_template_directory();
283
- break;
284
- case 'styles':
285
- case 'style':
286
- case 'stylesheets':
287
- case 'stylesheet':
288
- $retval = get_stylesheet_directory();
289
- break;
290
- case 'content':
291
- $retval = WP_CONTENT_DIR;
292
- break;
293
- case 'gallery':
294
- case 'galleries':
295
- $root_type = NGG_GALLERY_ROOT_TYPE;
296
- if ($root_type == 'content') {
297
- $retval = WP_CONTENT_DIR;
298
- } else {
299
- $retval = $this->_document_root;
300
- }
301
- break;
302
- default:
303
- $retval = $this->_document_root;
304
- }
305
- return wp_normalize_path($retval);
306
- }
307
- function get_absolute_path($path)
308
- {
309
- $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
310
- $absolutes = array();
311
- foreach ($parts as $part) {
312
- if ('.' == $part) {
313
- continue;
314
- }
315
- if ('..' == $part) {
316
- array_pop($absolutes);
317
- } else {
318
- $absolutes[] = $part;
319
- }
320
- }
321
- return wp_normalize_path(implode(DIRECTORY_SEPARATOR, $absolutes));
322
- }
323
- /**
324
- * Sets the document root for this application
325
- * @param string $value
326
- * @return string
327
- */
328
- function set_document_root($value)
329
- {
330
- // some web servers like home.pl and PhpStorm put the document root in "/" or (even weirder) "//"
331
- if ($value == DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR) {
332
- $value = DIRECTORY_SEPARATOR;
333
- }
334
- if ($value !== DIRECTORY_SEPARATOR) {
335
- $value = rtrim($value, "/\\");
336
- }
337
- return $this->_document_root = $value;
338
- }
339
  }
1
  <?php
2
  /**
3
  * Class C_Fs
4
+ *
5
  * @implements I_Fs
6
  */
7
  class C_Fs extends C_Component
28
  function define($context = FALSE)
29
  {
30
  parent::define($context);
 
31
  $this->implement('I_Fs');
32
  }
33
  function initialize()
35
  parent::initialize();
36
  $this->_document_root = $this->set_document_root(ABSPATH);
37
  }
38
+ /**
39
+ * Gets the document root for this application
40
+ * @param string $type Must be one of plugins, plugins_mu, templates, styles, content, gallery, or root
41
+ * @return string
42
+ */
43
+ function get_document_root($type = 'root')
44
+ {
45
+ $retval = NULL;
46
+ switch ($type) {
47
+ case 'plugins':
48
+ case 'plugin':
49
+ $retval = WP_PLUGIN_DIR;
50
+ break;
51
+ case 'plugins_mu':
52
+ case 'plugin_mu':
53
+ $retval = WPMU_PLUGIN_DIR;
54
+ break;
55
+ case 'templates':
56
+ case 'template':
57
+ case 'themes':
58
+ case 'theme':
59
+ $retval = get_template_directory();
60
+ break;
61
+ case 'styles':
62
+ case 'style':
63
+ case 'stylesheets':
64
+ case 'stylesheet':
65
+ $retval = get_stylesheet_directory();
66
+ break;
67
+ case 'content':
68
+ $retval = WP_CONTENT_DIR;
69
+ break;
70
+ case 'gallery':
71
+ case 'galleries':
72
+ $root_type = NGG_GALLERY_ROOT_TYPE;
73
+ if ($root_type == 'content') {
74
+ $retval = WP_CONTENT_DIR;
75
+ } else {
76
+ $retval = $this->_document_root;
77
+ }
78
+ break;
79
+ default:
80
+ $retval = $this->_document_root;
81
+ }
82
+ return wp_normalize_path($retval);
83
+ }
84
+ function get_absolute_path($path)
85
+ {
86
+ $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
87
+ $absolutes = array();
88
+ foreach ($parts as $part) {
89
+ if ('.' == $part) {
90
+ continue;
91
+ }
92
+ if ('..' == $part) {
93
+ array_pop($absolutes);
94
+ } else {
95
+ $absolutes[] = $part;
96
+ }
97
+ }
98
+ return wp_normalize_path(implode(DIRECTORY_SEPARATOR, $absolutes));
99
+ }
100
+ /**
101
+ * Sets the document root for this application
102
+ * @param string $value
103
+ * @return string
104
+ */
105
+ function set_document_root($value)
106
+ {
107
+ // some web servers like home.pl and PhpStorm put the document root in "/" or (even weirder) "//"
108
+ if ($value == DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR) {
109
+ $value = DIRECTORY_SEPARATOR;
110
+ }
111
+ if ($value !== DIRECTORY_SEPARATOR) {
112
+ $value = rtrim($value, "/\\");
113
+ }
114
+ return $this->_document_root = $value;
115
+ }
116
  function add_trailing_slash($path)
117
  {
118
  return rtrim($path, "/\\") . DIRECTORY_SEPARATOR;
332
  }
333
  return array($path, $module);
334
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  }
products/photocrati_nextgen/modules/i18n/module.i18n.php CHANGED
@@ -29,12 +29,6 @@ class M_I18N extends C_Base_Module
29
 
30
  function _register_adapters()
31
  {
32
- // Provides translating the name & description of images, albums, and galleries
33
- $this->get_registry()->add_adapter('I_Image_Mapper', 'A_I18N_Image_Translation');
34
- $this->get_registry()->add_adapter('I_Album_Mapper', 'A_I18N_Album_Translation');
35
- $this->get_registry()->add_adapter('I_Gallery_Mapper', 'A_I18N_Gallery_Translation');
36
- $this->get_registry()->add_adapter('I_Displayed_Gallery', 'A_I18N_Displayed_Gallery_Translation');
37
-
38
  // qTranslate requires we disable "Hide Untranslated Content" during routed app requests like
39
  // photocrati-ajax, when uploading new images, or retrieving dynamically altered (watermarked) images
40
  $this->get_registry()->add_adapter('I_Routing_App', 'A_I18N_Routing_App');
@@ -360,10 +354,6 @@ class M_I18N extends C_Base_Module
360
  function get_type_list()
361
  {
362
  return array(
363
- 'A_I18N_Displayed_Gallery_Translation' => 'adapter.i18n_displayed_gallery_translation.php',
364
- 'A_I18N_Image_Translation' => 'adapter.i18n_image_translation.php',
365
- 'A_I18N_Album_Translation' => 'adapter.i18n_album_translation.php',
366
- 'A_I18N_Gallery_Translation' => 'adapter.i18n_gallery_translation.php',
367
  'A_I18N_Routing_App' => 'adapter.i18n_routing_app.php'
368
  );
369
  }
29
 
30
  function _register_adapters()
31
  {
 
 
 
 
 
 
32
  // qTranslate requires we disable "Hide Untranslated Content" during routed app requests like
33
  // photocrati-ajax, when uploading new images, or retrieving dynamically altered (watermarked) images
34
  $this->get_registry()->add_adapter('I_Routing_App', 'A_I18N_Routing_App');
354
  function get_type_list()
355
  {
356
  return array(
 
 
 
 
357
  'A_I18N_Routing_App' => 'adapter.i18n_routing_app.php'
358
  );
359
  }
products/photocrati_nextgen/modules/i18n/package.module.i18n.php CHANGED
@@ -1,94 +1,4 @@
1
  <?php
2
- /**
3
- * Class A_I18N_Album_Translation
4
- * @mixin C_Album_Mapper
5
- * @adapts I_Album_Mapper
6
- */
7
- class A_I18N_Album_Translation extends Mixin
8
- {
9
- function set_defaults($entity)
10
- {
11
- $this->call_parent('set_defaults', $entity);
12
- if (!is_admin()) {
13
- if (!empty($entity->name)) {
14
- $entity->name = M_I18N::translate($entity->name, 'album_' . $entity->{$entity->id_field} . '_name');
15
- }
16
- if (!empty($entity->albumdesc)) {
17
- $entity->albumdesc = M_I18N::translate($entity->albumdesc, 'album_' . $entity->{$entity->id_field} . '_description');
18
- }
19
- // these fields are set when the album is a child to another album
20
- if (!empty($entity->title)) {
21
- $entity->title = M_I18N::translate($entity->title, 'album_' . $entity->{$entity->id_field} . '_name');
22
- }
23
- if (!empty($entity->galdesc)) {
24
- $entity->galdesc = M_I18N::translate($entity->galdesc, 'album_' . $entity->{$entity->id_field} . '_description');
25
- }
26
- }
27
- }
28
- }
29
- /**
30
- * Class A_I18N_Displayed_Gallery_Translation
31
- * @mixin C_Displayed_Gallery
32
- * @adapts I_Displayed_Gallery
33
- */
34
- class A_I18N_Displayed_Gallery_Translation extends Mixin
35
- {
36
- function _get_image_entities($source_obj, $limit, $offset, $id_only, $returns)
37
- {
38
- $results = $this->call_parent('_get_image_entities', $source_obj, $limit, $offset, $id_only, $returns);
39
- if (!is_admin() && in_array('image', $source_obj->returns)) {
40
- foreach ($results as $entity) {
41
- if (!empty($entity->description)) {
42
- $entity->description = M_I18N::translate($entity->description, 'pic_' . $entity->pid . '_description');
43
- }
44
- if (!empty($entity->alttext)) {
45
- $entity->alttext = M_I18N::translate($entity->alttext, 'pic_' . $entity->pid . '_alttext');
46
- }
47
- }
48
- }
49
- return $results;
50
- }
51
- }
52
- /**
53
- * Class A_I18N_Gallery_Translation
54
- * @mixin C_Gallery_Mapper
55
- * @adapts I_Gallery_Mapper
56
- */
57
- class A_I18N_Gallery_Translation extends Mixin
58
- {
59
- function set_defaults($entity)
60
- {
61
- $this->call_parent('set_defaults', $entity);
62
- if (!is_admin()) {
63
- if (!empty($entity->title)) {
64
- $entity->title = M_I18N::translate($entity->title, 'gallery_' . $entity->{$entity->id_field} . '_name');
65
- }
66
- if (!empty($entity->galdesc)) {
67
- $entity->galdesc = M_I18N::translate($entity->galdesc, 'gallery_' . $entity->{$entity->id_field} . '_description');
68
- }
69
- }
70
- }
71
- }
72
- /**
73
- * Class A_I18N_Image_Translation
74
- * @mixin C_Image_Mapper
75
- * @adapts I_Image_Mapper
76
- */
77
- class A_I18N_Image_Translation extends Mixin
78
- {
79
- function set_defaults($entity)
80
- {
81
- $this->call_parent('set_defaults', $entity);
82
- if (!is_admin()) {
83
- if (!empty($entity->description)) {
84
- $entity->description = M_I18N::translate($entity->description, 'pic_' . $entity->{$entity->id_field} . '_description');
85
- }
86
- if (!empty($entity->alttext)) {
87
- $entity->alttext = M_I18N::translate($entity->alttext, 'pic_' . $entity->{$entity->id_field} . '_alttext');
88
- }
89
- }
90
- }
91
- }
92
  /**
93
  * Class A_I18N_Routing_App
94
  * @mixin C_Routing_App
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  /**
3
  * Class A_I18N_Routing_App
4
  * @mixin C_Routing_App
products/photocrati_nextgen/modules/lightbox/package.module.lightbox.php CHANGED
@@ -318,8 +318,7 @@ class C_Lightbox_Library_Manager
318
  }
319
  /**
320
  * Represents a lightbox available in NextGEN Gallery
321
- * Class C_NGG_Lightbox
322
- * @mixin Mixin_NGG_Lightbox_Instance_Methods
323
  * @implements I_Lightbox
324
  */
325
  class C_NGG_Lightbox extends C_Component
@@ -327,7 +326,6 @@ class C_NGG_Lightbox extends C_Component
327
  function define($context = FALSE, $properties = array())
328
  {
329
  parent::define($context);
330
- $this->add_mixin('Mixin_NGG_Lightbox_Instance_Methods');
331
  $this->implement('I_Lightbox');
332
  }
333
  function initialize($name = '', $properties = array())
@@ -338,9 +336,6 @@ class C_NGG_Lightbox extends C_Component
338
  $this->{$k} = $v;
339
  }
340
  }
341
- }
342
- class Mixin_NGG_Lightbox_Instance_Methods extends Mixin
343
- {
344
  /**
345
  * Returns true/false whether or not the lightbox supports displaying entities from the displayed gallery object
346
  * @param $displayed_gallery. By default, lightboxes don't support albums
318
  }
319
  /**
320
  * Represents a lightbox available in NextGEN Gallery
321
+ *
 
322
  * @implements I_Lightbox
323
  */
324
  class C_NGG_Lightbox extends C_Component
326
  function define($context = FALSE, $properties = array())
327
  {
328
  parent::define($context);
 
329
  $this->implement('I_Lightbox');
330
  }
331
  function initialize($name = '', $properties = array())
336
  $this->{$k} = $v;
337
  }
338
  }
 
 
 
339
  /**
340
  * Returns true/false whether or not the lightbox supports displaying entities from the displayed gallery object
341
  * @param $displayed_gallery. By default, lightboxes don't support albums
products/photocrati_nextgen/modules/marketing/static/pro-mosaic-preview.jpg CHANGED
File without changes
products/photocrati_nextgen/modules/mvc/package.module.mvc.php CHANGED
@@ -110,17 +110,9 @@ class A_MVC_Fs extends Mixin
110
  if (preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) {
111
  die('You are not allowed to call this page directly.');
112
  }
113
- class Mixin_MVC_Controller_Defaults extends Mixin
114
- {
115
- // Provide a default view
116
- function index_action($return = FALSE)
117
- {
118
- return $this->render_view('photocrati-mvc#index', array(), $return);
119
- }
120
- }
121
  /**
122
  * Provides actions that are executed based on the requested url
123
- * @mixin Mixin_MVC_Controller_Defaults
124
  * @mixin Mixin_MVC_Controller_Instance_Methods
125
  * @implements I_MVC_Controller
126
  */
@@ -132,16 +124,9 @@ abstract class C_MVC_Controller extends C_Component
132
  function define($context = FALSE)
133
  {
134
  parent::define($context);
135
- $this->add_mixin('Mixin_MVC_Controller_Defaults');
136
  $this->add_mixin('Mixin_MVC_Controller_Instance_Methods');
137
  $this->implement('I_MVC_Controller');
138
  }
139
- }
140
- /**
141
- * Adds methods for MVC Controller
142
- */
143
- class Mixin_MVC_Controller_Instance_Methods extends Mixin
144
- {
145
  function set_content_type($type)
146
  {
147
  switch ($type) {
@@ -189,13 +174,6 @@ class Mixin_MVC_Controller_Instance_Methods extends Mixin
189
  $this->object->_content_type = $type;
190
  return $type;
191
  }
192
- function do_not_cache()
193
- {
194
- if (!headers_sent()) {
195
- header('Cache-Control: no-cache');
196
- header('Pragma: no-cache');
197
- }
198
- }
199
  function expires($time)
200
  {
201
  $time = strtotime($time);
@@ -229,6 +207,13 @@ class Mixin_MVC_Controller_Instance_Methods extends Mixin
229
  {
230
  return "PUT" == $this->object->get_router()->get_request_method();
231
  }
 
 
 
 
 
 
 
232
  function is_custom_request($type)
233
  {
234
  return strtolower($type) == strtolower($this->object->get_router()->get_request_method());
@@ -241,43 +226,12 @@ class Mixin_MVC_Controller_Instance_Methods extends Mixin
241
  {
242
  return $this->object->get_router()->get_routed_app();
243
  }
244
- /**
245
- * Returns the value of a parameters
246
- * @param string $key
247
- * @param string|null $prefix (optional)
248
- * @return string
249
- */
250
- function param($key, $prefix = NULL, $default = NULL)
251
- {
252
- return $this->object->get_routed_app()->get_parameter($key, $prefix, $default);
253
- }
254
- function set_param($key, $value, $id = NULL, $use_prefix = FALSE)
255
- {
256
- return $this->object->get_routed_app()->set_parameter($key, $value, $id, $use_prefix);
257
- }
258
- function set_param_for($url, $key, $value, $id = NULL, $use_prefix = FALSE)
259
- {
260
- return $this->object->get_routed_app()->set_parameter($key, $value, $id, $use_prefix, $url);
261
- }
262
- function remove_param($key, $id = NULL)
263
- {
264
- return $this->object->get_routed_app()->remove_parameter($key, $id);
265
- }
266
  function remove_param_for($url, $key, $id = NULL)
267
  {
268
  $app = $this->object->get_routed_app();
269
  $retval = $app->remove_parameter($key, $id, $url);
270
  return $retval;
271
  }
272
- /**
273
- * Gets the routed url, generated by the Routing App
274
- * @param bool $with_qs (optional) With QueryString
275
- * @return string
276
- */
277
- function get_routed_url($with_qs = FALSE)
278
- {
279
- return $this->object->get_routed_app()->get_app_url(FALSE, $with_qs);
280
- }
281
  /**
282
  * Gets the absolute path of a static resource
283
  * @param string $path
@@ -309,8 +263,60 @@ class Mixin_MVC_Controller_Instance_Methods extends Mixin
309
  $this->object->render();
310
  return $this->object->render_partial($name, $vars, $return);
311
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  /**
313
  * Outputs the response headers
 
 
314
  */
315
  function render()
316
  {
@@ -318,14 +324,6 @@ class Mixin_MVC_Controller_Instance_Methods extends Mixin
318
  header('Content-Type: ' . $this->object->_content_type . '; charset=' . get_option('blog_charset'), true);
319
  }
320
  }
321
- /**
322
- * Renders a view
323
- */
324
- function render_partial($template, $params = array(), $return = FALSE, $context = NULL)
325
- {
326
- $view = $this->object->create_view($template, $params, $context);
327
- return $view->render($return);
328
- }
329
  function create_view($template, $params = array(), $context = NULL)
330
  {
331
  if (!$context) {
@@ -361,9 +359,6 @@ class C_MVC_View extends C_Component
361
  $this->implement('I_MVC_View');
362
  $this->add_mixin('Mixin_Mvc_View_Instance_Methods');
363
  }
364
- }
365
- class Mixin_Mvc_View_Instance_Methods extends Mixin
366
- {
367
  /**
368
  * Returns the variables to be used in the template
369
  * @return array
@@ -395,31 +390,6 @@ class Mixin_Mvc_View_Instance_Methods extends Mixin
395
  }
396
  return $value;
397
  }
398
- /**
399
- * Renders the view (template)
400
- * @param bool $return (optional)
401
- * @return string|NULL
402
- */
403
- function render($return = FALSE)
404
- {
405
- $element = $this->object->render_object();
406
- $content = $this->object->rasterize_object($element);
407
- if (!$return) {
408
- echo $content;
409
- }
410
- return $content;
411
- }
412
- function render_object()
413
- {
414
- // We use underscores to prefix local variables to avoid conflicts wth
415
- // template vars
416
- $__element = $this->start_element($this->object->_template, 'template', $this->object);
417
- $template_vars = $this->object->get_template_vars();
418
- extract($template_vars);
419
- include $this->object->get_template_abspath();
420
- $this->end_element();
421
- return $__element;
422
- }
423
  function rasterize_object($element)
424
  {
425
  return $element->rasterize();
@@ -557,6 +527,34 @@ class Mixin_Mvc_View_Instance_Methods extends Mixin
557
  }
558
  return $retval;
559
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  /**
561
  * Adds a template parameter
562
  * @param $key
110
  if (preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) {
111
  die('You are not allowed to call this page directly.');
112
  }
 
 
 
 
 
 
 
 
113
  /**
114
  * Provides actions that are executed based on the requested url
115
+ *
116
  * @mixin Mixin_MVC_Controller_Instance_Methods
117
  * @implements I_MVC_Controller
118
  */
124
  function define($context = FALSE)
125
  {
126
  parent::define($context);
 
127
  $this->add_mixin('Mixin_MVC_Controller_Instance_Methods');
128
  $this->implement('I_MVC_Controller');
129
  }
 
 
 
 
 
 
130
  function set_content_type($type)
131
  {
132
  switch ($type) {
174
  $this->object->_content_type = $type;
175
  return $type;
176
  }
 
 
 
 
 
 
 
177
  function expires($time)
178
  {
179
  $time = strtotime($time);
207
  {
208
  return "PUT" == $this->object->get_router()->get_request_method();
209
  }
210
+ function do_not_cache()
211
+ {
212
+ if (!headers_sent()) {
213
+ header('Cache-Control: no-cache');
214
+ header('Pragma: no-cache');
215
+ }
216
+ }
217
  function is_custom_request($type)
218
  {
219
  return strtolower($type) == strtolower($this->object->get_router()->get_request_method());
226
  {
227
  return $this->object->get_router()->get_routed_app();
228
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  function remove_param_for($url, $key, $id = NULL)
230
  {
231
  $app = $this->object->get_routed_app();
232
  $retval = $app->remove_parameter($key, $id, $url);
233
  return $retval;
234
  }
 
 
 
 
 
 
 
 
 
235
  /**
236
  * Gets the absolute path of a static resource
237
  * @param string $path
263
  $this->object->render();
264
  return $this->object->render_partial($name, $vars, $return);
265
  }
266
+ /**
267
+ * Renders a view
268
+ */
269
+ function render_partial($template, $params = array(), $return = FALSE, $context = NULL)
270
+ {
271
+ $view = $this->object->create_view($template, $params, $context);
272
+ return $view->render($return);
273
+ }
274
+ }
275
+ /**
276
+ * Adds methods for MVC Controller
277
+ */
278
+ class Mixin_MVC_Controller_Instance_Methods extends Mixin
279
+ {
280
+ // Provide a default view
281
+ function index_action($return = FALSE)
282
+ {
283
+ return $this->render_view('photocrati-mvc#index', array(), $return);
284
+ }
285
+ /**
286
+ * Returns the value of a parameters
287
+ * @param string $key
288
+ * @param string|null $prefix (optional)
289
+ * @return string
290
+ */
291
+ function param($key, $prefix = NULL, $default = NULL)
292
+ {
293
+ return $this->object->get_routed_app()->get_parameter($key, $prefix, $default);
294
+ }
295
+ function set_param($key, $value, $id = NULL, $use_prefix = FALSE)
296
+ {
297
+ return $this->object->get_routed_app()->set_parameter($key, $value, $id, $use_prefix);
298
+ }
299
+ function set_param_for($url, $key, $value, $id = NULL, $use_prefix = FALSE)
300
+ {
301
+ return $this->object->get_routed_app()->set_parameter($key, $value, $id, $use_prefix, $url);
302
+ }
303
+ function remove_param($key, $id = NULL)
304
+ {
305
+ return $this->object->get_routed_app()->remove_parameter($key, $id);
306
+ }
307
+ /**
308
+ * Gets the routed url, generated by the Routing App
309
+ * @param bool $with_qs (optional) With QueryString
310
+ * @return string
311
+ */
312
+ function get_routed_url($with_qs = FALSE)
313
+ {
314
+ return $this->object->get_routed_app()->get_app_url(FALSE, $with_qs);
315
+ }
316
  /**
317
  * Outputs the response headers
318
+ *
319
+ * TODO: Determine if this can be moved into C_MVC_Controller
320
  */
321
  function render()
322
  {
324
  header('Content-Type: ' . $this->object->_content_type . '; charset=' . get_option('blog_charset'), true);
325
  }
326
  }
 
 
 
 
 
 
 
 
327
  function create_view($template, $params = array(), $context = NULL)
328
  {
329
  if (!$context) {
359
  $this->implement('I_MVC_View');
360
  $this->add_mixin('Mixin_Mvc_View_Instance_Methods');
361
  }
 
 
 
362
  /**
363
  * Returns the variables to be used in the template
364
  * @return array
390
  }
391
  return $value;
392
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  function rasterize_object($element)
394
  {
395
  return $element->rasterize();
527
  }
528
  return $retval;
529
  }
530
+ }
531
+ class Mixin_Mvc_View_Instance_Methods extends Mixin
532
+ {
533
+ /**
534
+ * Renders the view (template)
535
+ * @param bool $return (optional)
536
+ * @return string|NULL
537
+ */
538
+ function render($return = FALSE)
539
+ {
540
+ $element = $this->object->render_object();
541
+ $content = $this->object->rasterize_object($element);
542
+ if (!$return) {
543
+ echo $content;
544
+ }
545
+ return $content;
546
+ }
547
+ function render_object()
548
+ {
549
+ // We use underscores to prefix local variables to avoid conflicts wth
550
+ // template vars
551
+ $__element = $this->start_element($this->object->_template, 'template', $this->object);
552
+ $template_vars = $this->object->get_template_vars();
553
+ extract($template_vars);
554
+ include $this->object->get_template_abspath();
555
+ $this->end_element();
556
+ return $__element;
557
+ }
558
  /**
559
  * Adds a template parameter
560
  * @param $key
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/CHANGELOG.md CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/LICENSE.md CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/css/select2.css CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/css/select2.min.css CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/af.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/af.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ar.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ar.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/az.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/az.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bg.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bg.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bn.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bn.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bs.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/bs.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ca.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ca.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/cs.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/cs.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/da.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/da.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/de.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/de.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/dsb.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/dsb.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/el.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/el.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/en.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/en.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/es.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/es.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/et.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/et.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/eu.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/eu.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fa.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fa.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fi.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fi.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fr.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/fr.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/gl.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/gl.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/he.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/he.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hi.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hi.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hr.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hr.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hsb.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hsb.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hu.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hu.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hy.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/hy.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/id.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/id.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/is.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/is.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/it.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/it.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ja.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ja.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ka.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ka.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/km.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/km.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ko.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ko.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lt.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lt.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lv.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/lv.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/mk.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/mk.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ms.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ms.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nb.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nb.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ne.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ne.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nl.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/nl.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pl.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pl.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ps.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ps.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt-BR.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt-BR.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/pt.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ro.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ro.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ru.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/ru.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sk.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sk.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sl.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sl.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sq.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sq.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr-Cyrl.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr-Cyrl.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sr.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sv.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/sv.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/th.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/th.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tk.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tk.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tr.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/tr.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/uk.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/uk.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/vi.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/vi.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-CN.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-CN.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-TW.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/i18n/zh-TW.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full copy.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full copy.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_admin/static/select2-4.0.13/dist/js/select2.full.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_album/package.module.nextgen_basic_album.php CHANGED
@@ -795,7 +795,7 @@ class A_NextGen_Basic_Album_Routes extends Mixin
795
  // Get router
796
  $router = C_Router::get_instance();
797
  $app = $router->get_routed_app();
798
- $slug = '/' . C_NextGen_Settings::get_instance()->router_param_slug;
799
  $app->rewrite("{*}{$slug}/page/{\\d}{*}", "{1}{$slug}/nggpage--{2}{3}", FALSE, TRUE);
800
  $app->rewrite("{*}{$slug}/pid--{*}", "{1}{$slug}/pid--{2}", FALSE, TRUE);
801
  // avoid conflicts with imagebrowser
@@ -809,7 +809,7 @@ class A_NextGen_Basic_Album_Routes extends Mixin
809
  // Get router
810
  $router = C_Router::get_instance();
811
  $app = $router->get_routed_app();
812
- $slug = '/' . C_NextGen_Settings::get_instance()->router_param_slug;
813
  $app->rewrite("{*}{$slug}/album--{\\w}", "{1}{$slug}/{2}");
814
  $app->rewrite("{*}{$slug}/album--{\\w}/gallery--{\\w}", "{1}{$slug}/{2}/{3}");
815
  $app->rewrite("{*}{$slug}/album--{\\w}/gallery--{\\w}/{*}", "{1}{$slug}/{2}/{3}/{4}");
@@ -848,7 +848,7 @@ class A_NextGen_Basic_Album_Urls extends Mixin
848
  {
849
  $retval = $this->call_parent('remove_parameter', $key, $id, $url);
850
  $settings = C_NextGen_Settings::get_instance();
851
- $param_slug = preg_quote($settings->router_param_slug, '#');
852
  if (preg_match("#(/{$param_slug}/.*)album--#", $retval, $matches)) {
853
  $retval = str_replace($matches[0], $matches[1], $retval);
854
  }
795
  // Get router
796
  $router = C_Router::get_instance();
797
  $app = $router->get_routed_app();
798
+ $slug = '/' . C_NextGen_Settings::get_instance()->get('router_param_slug', 'nggallery');
799
  $app->rewrite("{*}{$slug}/page/{\\d}{*}", "{1}{$slug}/nggpage--{2}{3}", FALSE, TRUE);
800
  $app->rewrite("{*}{$slug}/pid--{*}", "{1}{$slug}/pid--{2}", FALSE, TRUE);
801
  // avoid conflicts with imagebrowser
809
  // Get router
810
  $router = C_Router::get_instance();
811
  $app = $router->get_routed_app();
812
+ $slug = '/' . C_NextGen_Settings::get_instance()->get('router_param_slug', 'nggallery');
813
  $app->rewrite("{*}{$slug}/album--{\\w}", "{1}{$slug}/{2}");
814
  $app->rewrite("{*}{$slug}/album--{\\w}/gallery--{\\w}", "{1}{$slug}/{2}/{3}");
815
  $app->rewrite("{*}{$slug}/album--{\\w}/gallery--{\\w}/{*}", "{1}{$slug}/{2}/{3}/{4}");
848
  {
849
  $retval = $this->call_parent('remove_parameter', $key, $id, $url);
850
  $settings = C_NextGen_Settings::get_instance();
851
+ $param_slug = preg_quote($settings->get('router_param_slug', 'nggallery'), '#');
852
  if (preg_match("#(/{$param_slug}/.*)album--#", $retval, $matches)) {
853
  $retval = str_replace($matches[0], $matches[1], $retval);
854
  }
products/photocrati_nextgen/modules/nextgen_basic_gallery/module.nextgen_basic_gallery.php CHANGED
@@ -134,7 +134,7 @@ class M_NextGen_Basic_Gallery extends C_Base_Module
134
 
135
  function define_routes($router)
136
  {
137
- $slug = '/'.C_NextGen_Settings::get_instance()->router_param_slug;
138
  $router->rewrite("{*}{$slug}{*}/image/{*}", "{1}{$slug}{2}/pid--{3}");
139
  $router->rewrite("{*}{$slug}{*}/slideshow/{*}", "{1}{$slug}{2}/show--" . NGG_BASIC_SLIDESHOW . "/{3}");
140
  $router->rewrite("{*}{$slug}{*}/thumbnails/{*}", "{1}{$slug}{2}/show--". NGG_BASIC_THUMBNAILS . "/{3}");
134
 
135
  function define_routes($router)
136
  {
137
+ $slug = '/' . C_NextGen_Settings::get_instance()->get('router_param_slug', 'nggallery');
138
  $router->rewrite("{*}{$slug}{*}/image/{*}", "{1}{$slug}{2}/pid--{3}");
139
  $router->rewrite("{*}{$slug}{*}/slideshow/{*}", "{1}{$slug}{2}/show--" . NGG_BASIC_SLIDESHOW . "/{3}");
140
  $router->rewrite("{*}{$slug}{*}/thumbnails/{*}", "{1}{$slug}{2}/show--". NGG_BASIC_THUMBNAILS . "/{3}");
products/photocrati_nextgen/modules/nextgen_basic_gallery/package.module.nextgen_basic_gallery.php CHANGED
@@ -177,7 +177,7 @@ class A_NextGen_Basic_Gallery_Urls extends Mixin
177
  $uri = explode('?', $retval);
178
  $uri = $uri[0];
179
  $settings = C_NextGen_Settings::get_instance();
180
- $regex = '#/' . $settings->router_param_slug . '.*(/?(slideshow|thumbnails|imagebrowser)/?)#';
181
  if (preg_match($regex, $retval, $matches)) {
182
  $retval = str_replace($matches[1], '', $retval);
183
  }
@@ -189,7 +189,7 @@ class A_NextGen_Basic_Gallery_Urls extends Mixin
189
  // Get the settings manager
190
  $settings = C_NextGen_Settings::get_instance();
191
  // Create regex pattern
192
- $param_slug = preg_quote($settings->router_param_slug, '#');
193
  if ($key == 'nggpage') {
194
  $regex = "#(/{$param_slug}/.*)(/?page/\\d+/?)(.*)#";
195
  if (preg_match($regex, $retval, $matches)) {
177
  $uri = explode('?', $retval);
178
  $uri = $uri[0];
179
  $settings = C_NextGen_Settings::get_instance();
180
+ $regex = '#/' . $settings->get('router_param_slug', 'nggallery') . '.*(/?(slideshow|thumbnails|imagebrowser)/?)#';
181
  if (preg_match($regex, $retval, $matches)) {
182
  $retval = str_replace($matches[1], '', $retval);
183
  }
189
  // Get the settings manager
190
  $settings = C_NextGen_Settings::get_instance();
191
  // Create regex pattern
192
+ $param_slug = preg_quote($settings->get('router_param_slug', 'nggallery'), '#');
193
  if ($key == 'nggpage') {
194
  $regex = "#(/{$param_slug}/.*)(/?page/\\d+/?)(.*)#";
195
  if (preg_match($regex, $retval, $matches)) {
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/ajax-loader.gif CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/config.rb CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.eot CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.svg CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.ttf CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/fonts/slick.woff CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-1.8.0-modded.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-1.8.0-modded.min.js CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.css CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.less CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.min.css CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick-theme.scss CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.css CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.less CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.min.css CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow/slick/slick.scss CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/slideshow_preview.jpg CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_gallery/static/thumb_preview.jpg CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_imagebrowser/module.nextgen_basic_imagebrowser.php CHANGED
@@ -66,7 +66,7 @@ class M_NextGen_Basic_ImageBrowser extends C_Base_Module
66
 
67
  function define_routes($router)
68
  {
69
- $slug = '/'.C_NextGen_Settings::get_instance()->router_param_slug;
70
  $router->rewrite("{*}{$slug}{*}/image/{\\w}", "{1}{$slug}{2}/pid--{3}");
71
  }
72
 
66
 
67
  function define_routes($router)
68
  {
69
+ $slug = '/' . C_NextGen_Settings::get_instance()->get('router_param_slug', 'nggallery');
70
  $router->rewrite("{*}{$slug}{*}/image/{\\w}", "{1}{$slug}{2}/pid--{3}");
71
  }
72
 
products/photocrati_nextgen/modules/nextgen_basic_imagebrowser/static/preview.jpg CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_basic_tagcloud/module.nextgen_basic_tagcloud.php CHANGED
@@ -104,7 +104,7 @@ class M_NextGen_Basic_Tagcloud extends C_Base_Module
104
 
105
  function define_routes($router)
106
  {
107
- $slug = '/'.C_NextGen_Settings::get_instance()->router_param_slug;
108
  $router->rewrite("{*}{$slug}{*}/tags/{\\w}{*}", "{1}{$slug}{2}/gallerytag--{3}{4}");
109
  }
110
 
104
 
105
  function define_routes($router)
106
  {
107
+ $slug = '/' . C_NextGen_Settings::get_instance()->get('router_param_slug', 'nggallery');
108
  $router->rewrite("{*}{$slug}{*}/tags/{\\w}{*}", "{1}{$slug}{2}/gallerytag--{3}{4}");
109
  }
110
 
products/photocrati_nextgen/modules/nextgen_basic_tagcloud/package.module.nextgen_basic_tagcloud.php CHANGED
@@ -195,11 +195,11 @@ class A_NextGen_Basic_TagCloud_Urls extends Mixin
195
  // Get the settings manager
196
  $settings = C_NextGen_Settings::get_instance();
197
  // Create the regex pattern
198
- $sep = preg_quote($settings->router_param_separator, '#');
199
  if ($id) {
200
  $id = preg_quote($id, '#') . $sep;
201
  }
202
- $prefix = preg_quote($settings->router_param_prefix, '#');
203
  $regex = implode('', array('#//?', $id ? "({$id})?" : "(\\w+{$sep})?", "({$prefix})?gallerytag{$sep}([\\w\\-_]+)/?#"));
204
  // Replace any page parameters with the ngglegacy equivalent
205
  if (preg_match($regex, $retval, $matches)) {
195
  // Get the settings manager
196
  $settings = C_NextGen_Settings::get_instance();
197
  // Create the regex pattern
198
+ $sep = preg_quote($settings->get('router_param_separator', '--'), '#');
199
  if ($id) {
200
  $id = preg_quote($id, '#') . $sep;
201
  }
202
+ $prefix = preg_quote($settings->get('router_param_prefix', ''), '#');
203
  $regex = implode('', array('#//?', $id ? "({$id})?" : "(\\w+{$sep})?", "({$prefix})?gallerytag{$sep}([\\w\\-_]+)/?#"));
204
  // Replace any page parameters with the ngglegacy equivalent
205
  if (preg_match($regex, $retval, $matches)) {
products/photocrati_nextgen/modules/nextgen_basic_tagcloud/static/preview.gif CHANGED
File without changes
products/photocrati_nextgen/modules/nextgen_data/module.nextgen_data.php CHANGED
@@ -185,11 +185,9 @@ class M_NextGen_Data extends C_Base_Module
185
  'C_Ngglegacy_Thumbnail' => 'class.ngglegacy_thumbnail.php',
186
  'C_Dynamic_Thumbnails_Manager' => 'class.dynamic_thumbnails_manager.php',
187
  'Mixin_NextGen_Table_Extras' => 'mixin.nextgen_table_extras.php',
188
- 'Mixin_GalleryStorage_Base' => 'mixin.gallerystorage_base.php',
189
  'Mixin_GalleryStorage_Base_Dynamic' => 'mixin.gallerystorage_base_dynamic.php',
190
  'Mixin_GalleryStorage_Base_Getters' => 'mixin.gallerystorage_base_getters.php',
191
  'Mixin_GalleryStorage_Base_Management' => 'mixin.gallerystorage_base_management.php',
192
- 'Mixin_GalleryStorage_Base_MediaLibrary' => 'mixin.gallerystorage_base_medialibrary.php',
193
  'Mixin_GalleryStorage_Base_Upload' => 'mixin.gallerystorage_base_upload.php'
194
 
195
  );
185
  'C_Ngglegacy_Thumbnail' => 'class.ngglegacy_thumbnail.php',
186
  'C_Dynamic_Thumbnails_Manager' => 'class.dynamic_thumbnails_manager.php',
187
  'Mixin_NextGen_Table_Extras' => 'mixin.nextgen_table_extras.php',
 
188
  'Mixin_GalleryStorage_Base_Dynamic' => 'mixin.gallerystorage_base_dynamic.php',
189
  'Mixin_GalleryStorage_Base_Getters' => 'mixin.gallerystorage_base_getters.php',
190
  'Mixin_GalleryStorage_Base_Management' => 'mixin.gallerystorage_base_management.php',
 
191
  'Mixin_GalleryStorage_Base_Upload' => 'mixin.gallerystorage_base_upload.php'
192
 
193
  );
products/photocrati_nextgen/modules/nextgen_data/package.module.nextgen_data.php CHANGED
@@ -188,6 +188,14 @@ class C_Album_Mapper extends C_CustomTable_DataMapper_Driver
188
  }
189
  return self::$_instance;
190
  }
 
 
 
 
 
 
 
 
191
  }
192
  /**
193
  * Provides album-specific methods for the datamapper
@@ -212,14 +220,6 @@ class Mixin_Album_Mapper extends Mixin
212
  }
213
  return $retval;
214
  }
215
- /**
216
- * @param string $slug
217
- * @return null|stdClass|C_Album
218
- */
219
- public function get_by_slug($slug)
220
- {
221
- return array_pop($this->object->select()->where(['slug = %s', sanitize_title($slug)])->limit(1)->run_query());
222
- }
223
  /**
224
  * Sets the defaults for an album
225
  * @param C_DataMapper_Model|C_Album|stdClass $entity
@@ -234,6 +234,21 @@ class Mixin_Album_Mapper extends Mixin
234
  if (isset($entity->name) && !isset($entity->slug)) {
235
  $entity->slug = nggdb::get_unique_slug(sanitize_title($entity->name), 'album');
236
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  }
238
  }
239
  class Mixin_Dynamic_Thumbnails_Manager extends Mixin
@@ -796,6 +811,43 @@ class C_Exif_Writer
796
  return in_array(strtolower($extension), array('jpeg', 'jpg', 'jpeg_backup', 'jpg_backup')) ? TRUE : FALSE;
797
  }
798
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
799
  class Mixin_NextGen_Gallery_Validation
800
  {
801
  /**
@@ -879,43 +931,6 @@ class Mixin_NextGen_Gallery_Validation
879
  return $this->object->is_valid();
880
  }
881
  }
882
- /**
883
- * Creates a model representing a NextGEN Gallery object
884
- * @mixin Mixin_NextGen_Gallery_Validation
885
- * @implements I_Gallery
886
- */
887
- class C_Gallery extends C_DataMapper_Model
888
- {
889
- var $_mapper_interface = 'I_Gallery_Mapper';
890
- /**
891
- * Defines the interfaces and methods (through extensions and hooks)
892
- * that this class provides
893
- */
894
- function define($properties = array(), $mapper = FALSE, $context = FALSE)
895
- {
896
- parent::define($mapper, $properties, $context);
897
- $this->add_mixin('Mixin_NextGen_Gallery_Validation');
898
- $this->implement('I_Gallery');
899
- }
900
- /**
901
- * Instantiates a new model
902
- * @param array|stdClass $properties (optional)
903
- * @param C_Gallery_Mapper|false $mapper (optional)
904
- * @param string|bool $context (optional)
905
- */
906
- function initialize($properties = array(), $mapper = FALSE, $context = FALSE)
907
- {
908
- if (!$mapper) {
909
- $mapper = $this->get_registry()->get_utility($this->_mapper_interface);
910
- }
911
- parent::initialize($mapper, $properties);
912
- }
913
- function get_images()
914
- {
915
- $mapper = C_Image_Mapper::get_instance();
916
- return $mapper->select()->where(array('galleryid = %d', $this->gid))->order_by('sortorder')->run_query();
917
- }
918
- }
919
  /**
920
  * Provides a datamapper for galleries
921
  * @mixin Mixin_NextGen_Table_Extras
@@ -972,18 +987,6 @@ class C_Gallery_Mapper extends C_CustomTable_DataMapper_Driver
972
  }
973
  return self::$_instance;
974
  }
975
- }
976
- class Mixin_Gallery_Mapper extends Mixin
977
- {
978
- /**
979
- * Uses the title property as the post title when the Custom Post driver is used
980
- * @param object $entity
981
- * @return string
982
- */
983
- function get_post_title($entity)
984
- {
985
- return $entity->title;
986
- }
987
  /**
988
  * @param string $slug
989
  * @return C_Gallery|stdClass|null
@@ -999,6 +1002,41 @@ class Mixin_Gallery_Mapper extends Mixin
999
  }
1000
  return reset($retval);
1001
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1002
  function _save_entity($entity)
1003
  {
1004
  $storage = C_Gallery_Storage::get_instance();
@@ -1078,29 +1116,6 @@ class Mixin_Gallery_Mapper extends Mixin
1078
  }
1079
  return $retval;
1080
  }
1081
- function set_preview_image($gallery, $image, $only_if_empty = FALSE)
1082
- {
1083
- $retval = FALSE;
1084
- // We need the gallery object
1085
- if (is_numeric($gallery)) {
1086
- $gallery = $this->object->find($gallery);
1087
- }
1088
- // We need the image id
1089
- if (!is_numeric($image)) {
1090
- if (method_exists($image, 'id')) {
1091
- $image = $image->id();
1092
- } else {
1093
- $image = $image->{$image->id_field};
1094
- }
1095
- }
1096
- if ($gallery && $image) {
1097
- if ($only_if_empty && !$gallery->previewpic or !$only_if_empty) {
1098
- $gallery->previewpic = $image;
1099
- $retval = $this->object->save($gallery);
1100
- }
1101
- }
1102
- return $retval;
1103
- }
1104
  /**
1105
  * Sets default values for the gallery
1106
  * @param object $entity
@@ -1110,6 +1125,14 @@ class Mixin_Gallery_Mapper extends Mixin
1110
  // If author is missing, then set to the current user id
1111
  // TODO: Using wordpress function. Should use abstraction
1112
  $this->object->_set_default_value($entity, 'author', get_current_user_id());
 
 
 
 
 
 
 
 
1113
  }
1114
  }
1115
  class E_UploadException extends E_NggErrorException
@@ -1173,25 +1196,23 @@ class E_No_Image_Library_Exception extends E_NggErrorException
1173
  }
1174
  /**
1175
  * Class C_Gallery_Storage
 
1176
  * @implements I_Gallery_Storage
1177
- * @mixin Mixin_GalleryStorage_Base
1178
  * @mixin Mixin_GalleryStorage_Base_Dynamic
1179
  * @mixin Mixin_GalleryStorage_Base_Getters
1180
  * @mixin Mixin_GalleryStorage_Base_Management
1181
- * @mixin Mixin_GalleryStorage_Base_MediaLibrary
1182
  * @mixin Mixin_GalleryStorage_Base_Upload
1183
  */
1184
  class C_Gallery_Storage extends C_Component
1185
  {
1186
  public static $_instances = array();
 
1187
  function define($context = FALSE)
1188
  {
1189
  parent::define($context);
1190
- $this->add_mixin('Mixin_GalleryStorage_Base');
1191
  $this->add_mixin('Mixin_GalleryStorage_Base_Dynamic');
1192
  $this->add_mixin('Mixin_GalleryStorage_Base_Getters');
1193
  $this->add_mixin('Mixin_GalleryStorage_Base_Management');
1194
- $this->add_mixin('Mixin_GalleryStorage_Base_MediaLibrary');
1195
  $this->add_mixin('Mixin_GalleryStorage_Base_Upload');
1196
  $this->implement('I_Gallery_Storage');
1197
  $this->implement('I_GalleryStorage_Driver');
@@ -1242,4550 +1263,4542 @@ class C_Gallery_Storage extends C_Component
1242
  }
1243
  return self::$_instances[$context];
1244
  }
1245
- }
1246
- class Mixin_NextGen_Gallery_Image_Validation extends Mixin
1247
- {
1248
- function validation()
 
 
 
1249
  {
1250
- // Additional checks...
1251
- if (isset($this->object->description)) {
1252
- $this->object->description = M_NextGen_Data::strip_html($this->object->description, TRUE);
1253
- }
1254
- if (isset($this->object->alttext)) {
1255
- $this->object->alttext = M_NextGen_Data::strip_html($this->object->alttext, TRUE);
 
 
1256
  }
1257
- $this->validates_presence_of('galleryid', 'filename', 'alttext', 'exclude', 'sortorder', 'imagedate');
1258
- $this->validates_numericality_of('galleryid');
1259
- $this->validates_numericality_of($this->id());
1260
- $this->validates_numericality_of('sortorder');
1261
- $this->validates_length_of('filename', 185, '<=', __('Image filenames may not be longer than 185 characters in length', 'nextgen-gallery'));
1262
- return $this->object->is_valid();
1263
- }
1264
- }
1265
- /**
1266
- * Model for NextGen Gallery Images
1267
- * @mixin Mixin_NextGen_Gallery_Image_Validation
1268
- * @implements I_Image
1269
- */
1270
- class C_Image extends C_DataMapper_Model
1271
- {
1272
- var $_mapper_interface = 'I_Image_Mapper';
1273
- function define($properties = array(), $mapper = FALSE, $context = FALSE)
1274
- {
1275
- parent::define($mapper, $properties, $context);
1276
- $this->add_mixin('Mixin_NextGen_Gallery_Image_Validation');
1277
- $this->implement('I_Image');
1278
  }
1279
  /**
1280
- * Instantiates a new model
1281
- * @param array|stdClass $properties (optional)
1282
- * @param C_Image_Mapper|false $mapper (optional)
1283
- * @param string|false $context (optional)
1284
  */
1285
- function initialize($properties = array(), $mapper = FALSE, $context = FALSE)
1286
  {
1287
- if (!$mapper) {
1288
- $mapper = $this->get_registry()->get_utility($this->_mapper_interface);
 
 
 
 
 
 
1289
  }
1290
- parent::initialize($mapper, $properties);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1291
  }
1292
  /**
1293
- * Returns the model representing the gallery associated with this image
1294
- * @param object|false $model (optional)
1295
- * @return C_Gallery|object
1296
- */
1297
- function get_gallery($model = FALSE)
1298
- {
1299
- return C_Gallery_Mapper::get_instance()->find($this->galleryid, $model);
1300
- }
1301
- }
1302
- /**
1303
- * Class C_Image_Mapper
1304
- * @mixin Mixin_NextGen_Table_Extras
1305
- * @mixin Mixin_Gallery_Image_Mapper
1306
- * @implements I_Image_Mapper
1307
- */
1308
- class C_Image_Mapper extends C_CustomTable_DataMapper_Driver
1309
- {
1310
- public static $_instance = NULL;
1311
- /**
1312
- * Defines the gallery image mapper
1313
- * @param string|false $context (optional)
1314
- * @param mixed $not_used
1315
- */
1316
- function define($context = FALSE, $not_used = FALSE)
1317
- {
1318
- // Add 'attachment' context
1319
- if (!is_array($context)) {
1320
- $context = array($context);
1321
- }
1322
- array_push($context, 'attachment');
1323
- // Define the mapper
1324
- $this->_primary_key_column = 'pid';
1325
- parent::define('ngg_pictures', $context);
1326
- $this->add_mixin('Mixin_NextGen_Table_Extras');
1327
- $this->add_mixin('Mixin_Gallery_Image_Mapper');
1328
- $this->implement('I_Image_Mapper');
1329
- $this->set_model_factory_method('image');
1330
- // Define the columns
1331
- $this->define_column('pid', 'BIGINT', 0);
1332
- $this->define_column('image_slug', 'VARCHAR(255)');
1333
- $this->define_column('post_id', 'BIGINT', 0);
1334
- $this->define_column('galleryid', 'BIGINT', 0);
1335
- $this->define_column('filename', 'VARCHAR(255)');
1336
- $this->define_column('description', 'TEXT');
1337
- $this->define_column('alttext', 'TEXT');
1338
- $this->define_column('imagedate', 'DATETIME');
1339
- $this->define_column('exclude', 'INT', 0);
1340
- $this->define_column('sortorder', 'BIGINT', 0);
1341
- $this->define_column('meta_data', 'TEXT');
1342
- $this->define_column('extras_post_id', 'BIGINT', 0);
1343
- $this->define_column('updated_at', 'BIGINT');
1344
- // Mark the columns which should be unserialized
1345
- $this->add_serialized_column('meta_data');
1346
- }
1347
- function initialize($object_name = FALSE)
1348
- {
1349
- parent::initialize('ngg_pictures');
1350
- }
1351
- /**
1352
- * @param bool|string $context
1353
- * @return C_Image_Mapper
1354
  */
1355
- static function get_instance($context = False)
1356
  {
1357
- if (is_null(self::$_instance)) {
1358
- $klass = get_class();
1359
- self::$_instance = new $klass($context);
 
 
1360
  }
1361
- return self::$_instance;
1362
- }
1363
- }
1364
- /**
1365
- * Sets the alttext property as the post title
1366
- */
1367
- class Mixin_Gallery_Image_Mapper extends Mixin
1368
- {
1369
- function destroy($image)
1370
- {
1371
- $retval = $this->call_parent('destroy', $image);
1372
- // Delete tag associations with the image
1373
- if (!is_numeric($image)) {
1374
- $image = $image->{$image->id_field};
1375
  }
1376
- wp_delete_object_term_relationships($image, 'ngg_tag');
1377
- C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
1378
- return $retval;
1379
- }
1380
- function _save_entity($entity)
1381
- {
1382
- $entity->updated_at = time();
1383
- // If successfully saved then import metadata
1384
- $retval = $this->call_parent('_save_entity', $entity);
1385
- if ($retval) {
1386
- include_once NGGALLERY_ABSPATH . '/admin/functions.php';
1387
- $image_id = $this->get_id($entity);
1388
- if (!isset($entity->meta_data['saved'])) {
1389
- nggAdmin::import_MetaData($image_id);
1390
  }
1391
- C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
1392
  }
1393
  return $retval;
1394
  }
1395
- function reimport_metadata($image_or_id)
1396
  {
1397
- // Get the image
1398
- $image = NULL;
1399
- if (is_int($image_or_id)) {
1400
- $image = $this->object->find($image_or_id);
1401
- } else {
1402
- $image = $image_or_id;
1403
- }
1404
- // Reset all image details that would have normally been imported
1405
- if (is_array($image->meta_data)) {
1406
- unset($image->meta_data['saved']);
1407
- }
1408
- nggAdmin::import_MetaData($image);
1409
- return $this->object->save($image);
1410
  }
1411
  /**
1412
- * Retrieves the id from an image
1413
- * @param $image
1414
- * @return bool
1415
  */
1416
- function get_id($image)
1417
  {
1418
- $retval = FALSE;
1419
- // Have we been passed an entity and is the id_field set?
1420
- if ($image instanceof stdClass) {
1421
- if (isset($image->id_field)) {
1422
- $retval = $image->{$image->id_field};
1423
- }
1424
- } else {
1425
- $retval = $image->id();
1426
- }
1427
- // If we still don't have an id, then we'll lookup the primary key
1428
- // and try fetching it manually
1429
- if (!$retval) {
1430
- $key = $this->object->get_primary_key_column();
1431
- $retval = $image->{$key};
1432
- }
1433
- return $retval;
1434
  }
1435
- function get_post_title($entity)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1436
  {
1437
- return $entity->alttext;
 
 
 
 
 
 
 
 
1438
  }
1439
- function set_defaults($entity)
 
 
 
 
 
 
 
 
1440
  {
1441
- // If not set already, we'll add an exclude property. This is used
1442
- // by NextGEN Gallery itself, as well as the Attach to Post module
1443
- $this->object->_set_default_value($entity, 'exclude', 0);
1444
- // Ensure that the object has a description attribute
1445
- $this->object->_set_default_value($entity, 'description', '');
1446
- // If not set already, set a default sortorder
1447
- $this->object->_set_default_value($entity, 'sortorder', 0);
1448
- // The imagedate must be set
1449
- if (!isset($entity->imagedate) or is_null($entity->imagedate) or $entity->imagedate == '0000-00-00 00:00:00') {
1450
- $entity->imagedate = date("Y-m-d H:i:s");
1451
- }
1452
- // If a filename is set, and no alttext is set, then set the alttext
1453
- // to the basename of the filename (legacy behavior)
1454
- if (isset($entity->filename)) {
1455
- $path_parts = M_I18n::mb_pathinfo($entity->filename);
1456
- $alttext = !isset($path_parts['filename']) ? substr($path_parts['basename'], 0, strpos($path_parts['basename'], '.')) : $path_parts['filename'];
1457
- $this->object->_set_default_value($entity, 'alttext', $alttext);
1458
- }
1459
- // Set unique slug
1460
- if (isset($entity->alttext) && empty($entity->image_slug)) {
1461
- $entity->image_slug = nggdb::get_unique_slug(sanitize_title_with_dashes($entity->alttext), 'image');
1462
  }
1463
- // Ensure that the exclude parameter is an integer or boolean-evaluated
1464
- // value
1465
- if (is_string($entity->exclude)) {
1466
- $entity->exclude = intval($entity->exclude);
 
 
 
1467
  }
1468
- // Trim alttext and description
1469
- $entity->description = trim($entity->description);
1470
- $entity->alttext = trim($entity->alttext);
1471
  }
1472
  /**
1473
- * Finds all images for a gallery
1474
- * @param $gallery
1475
- * @param bool $model
1476
- *
1477
- * @return array
1478
  */
1479
- function find_all_for_gallery($gallery, $model = FALSE)
1480
  {
1481
- $retval = array();
1482
- $gallery_id = 0;
1483
- if (is_object($gallery)) {
1484
- if (isset($gallery->id_field)) {
1485
- $gallery_id = $gallery->{$gallery->id_field};
1486
- } else {
1487
- $key = $this->object->get_primary_key_column();
1488
- if (isset($gallery->{$key})) {
1489
- $gallery_id = $gallery->{$key};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1490
  }
1491
  }
1492
- } elseif (is_numeric($gallery)) {
1493
- $gallery_id = $gallery;
1494
- }
1495
- if ($gallery_id) {
1496
- $retval = $this->object->select()->where(array("galleryid = %s", $gallery_id))->run_query(FALSE, $model);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1497
  }
1498
- return $retval;
1499
  }
1500
- }
1501
- /**
1502
- * This class provides a lazy-loading wrapper to the NextGen-Legacy "nggImage" class for use in legacy style templates
1503
- */
1504
- class C_Image_Wrapper
1505
- {
1506
- public $_cache;
1507
- // cache of retrieved values
1508
- public $_settings;
1509
- // I_Settings_Manager cache
1510
- public $_storage;
1511
- // I_Gallery_Storage cache
1512
- public $_galleries;
1513
- // cache of I_Gallery_Mapper (plural)
1514
- public $_orig_image;
1515
- // original provided image
1516
- public $_orig_image_id;
1517
- // original image ID
1518
- public $_cache_overrides;
1519
- // allow for forcing variable values
1520
- public $_legacy = FALSE;
1521
- public $_displayed_gallery;
1522
- // cached object
1523
  /**
1524
- * Constructor. Converts the image class into an array and fills from defaults any missing values
1525
- *
1526
- * @param object $image Individual result from displayed_gallery->get_entities()
1527
- * @param object $displayed_gallery Displayed gallery -- MAY BE NULL
1528
- * @param bool $legacy Whether the image source is from NextGen Legacy or NextGen
1529
- * @return void
1530
  */
1531
- public function __construct($image, $displayed_gallery = NULL, $legacy = FALSE)
1532
  {
1533
- // for clarity
1534
- if ($displayed_gallery && isset($displayed_gallery->display_settings['number_of_columns'])) {
1535
- $columns = $displayed_gallery->display_settings['number_of_columns'];
1536
- } else {
1537
- $columns = 0;
1538
- }
1539
- // Public variables
1540
- $defaults = array(
1541
- 'errmsg' => '',
1542
- // Error message to display, if any
1543
- 'error' => FALSE,
1544
- // Error state
1545
- 'imageURL' => '',
1546
- // URL Path to the image
1547
- 'thumbURL' => '',
1548
- // URL Path to the thumbnail
1549
- 'imagePath' => '',
1550
- // Server Path to the image
1551
- 'thumbPath' => '',
1552
- // Server Path to the thumbnail
1553
- 'href' => '',
1554
- // A href link code
1555
- // Mostly constant
1556
- 'thumbPrefix' => 'thumbs_',
1557
- // FolderPrefix to the thumbnail
1558
- 'thumbFolder' => '/thumbs/',
1559
- // Foldername to the thumbnail
1560
- // Image Data
1561
- 'galleryid' => 0,
1562
- // Gallery ID
1563
- 'pid' => 0,
1564
- // Image ID
1565
- 'filename' => '',
1566
- // Image filename
1567
- 'description' => '',
1568
- // Image description
1569
- 'alttext' => '',
1570
- // Image alttext
1571
- 'imagedate' => '',
1572
- // Image date/time
1573
- 'exclude' => '',
1574
- // Image exclude
1575
- 'thumbcode' => '',
1576
- // Image effect code
1577
- // Gallery Data
1578
- 'name' => '',
1579
- // Gallery name
1580
- 'path' => '',
1581
- // Gallery path
1582
- 'title' => '',
1583
- // Gallery title
1584
- 'pageid' => 0,
1585
- // Gallery page ID
1586
- 'previewpic' => 0,
1587
- // Gallery preview pic
1588
- 'style' => $columns > 0 ? 'style="width:' . floor(100 / $columns) . '%;"' : '',
1589
- 'hidden' => FALSE,
1590
- 'permalink' => '',
1591
- 'tags' => '',
1592
- );
1593
- // convert the image to an array and apply the defaults
1594
- $this->_orig_image = $image;
1595
- $image = (array) $image;
1596
- foreach ($defaults as $key => $val) {
1597
- if (!isset($image[$key])) {
1598
- $image[$key] = $val;
1599
- }
1600
  }
1601
- // cache the results
1602
- ksort($image);
1603
- $id_field = !empty($image['id_field']) ? $image['id_field'] : 'pid';
1604
- $this->_cache = (array) apply_filters('ngg_image_object', (object) $image, $image[$id_field]);
1605
- $this->_orig_image_id = $image[$id_field];
1606
- $this->_legacy = $legacy;
1607
- $this->_displayed_gallery = $displayed_gallery;
1608
- }
1609
- public function __set($name, $value)
1610
- {
1611
- $this->_cache[$name] = $value;
1612
- }
1613
- public function __isset($name)
1614
- {
1615
- return isset($this->_cache[$name]);
1616
- }
1617
- public function __unset($name)
1618
- {
1619
- unset($this->_cache[$name]);
1620
  }
1621
  /**
1622
- * Lazy-loader for image variables.
1623
- *
1624
- * @param string $name Parameter name
1625
- * @return mixed
 
1626
  */
1627
- public function __get($name)
1628
  {
1629
- if (isset($this->_cache_overrides[$name])) {
1630
- return $this->_cache_overrides[$name];
1631
- }
1632
- // at the bottom we default to returning $this->_cache[$name].
1633
- switch ($name) {
1634
- case 'alttext':
1635
- $this->_cache['alttext'] = empty($this->_cache['alttext']) ? ' ' : html_entity_decode(stripslashes($this->_cache['alttext']));
1636
- return $this->_cache['alttext'];
1637
- case 'author':
1638
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1639
- $this->_cache['author'] = $gallery->name;
1640
- return $this->_cache['author'];
1641
- case 'caption':
1642
- $caption = html_entity_decode(stripslashes($this->__get('description')));
1643
- if (empty($caption)) {
1644
- $caption = '&nbsp;';
1645
- }
1646
- $this->_cache['caption'] = $caption;
1647
- return $this->_cache['caption'];
1648
- case 'description':
1649
- $this->_cache['description'] = empty($this->_cache['description']) ? ' ' : html_entity_decode(stripslashes($this->_cache['description']));
1650
- return $this->_cache['description'];
1651
- case 'galdesc':
1652
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1653
- $this->_cache['galdesc'] = $gallery->name;
1654
- return $this->_cache['galdesc'];
1655
- case 'gid':
1656
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1657
- $this->_cache['gid'] = $gallery->{$gallery->id_field};
1658
- return $this->_cache['gid'];
1659
- case 'href':
1660
- return $this->__get('imageHTML');
1661
- case 'id':
1662
- return $this->_orig_image_id;
1663
- case 'imageHTML':
1664
- $tmp = '<a href="' . $this->__get('imageURL') . '" title="' . htmlspecialchars(stripslashes($this->__get('description'))) . '" ' . $this->get_thumbcode($this->__get('name')) . '>' . '<img alt="' . $this->__get('alttext') . '" src="' . $this->__get('imageURL') . '"/>' . '</a>';
1665
- $this->_cache['href'] = $tmp;
1666
- $this->_cache['imageHTML'] = $tmp;
1667
- return $this->_cache['imageHTML'];
1668
- case 'imagePath':
1669
- $storage = $this->get_storage();
1670
- $this->_cache['imagePath'] = $storage->get_image_abspath($this->_orig_image, 'full');
1671
- return $this->_cache['imagePath'];
1672
- case 'imageURL':
1673
- $storage = $this->get_storage();
1674
- $this->_cache['imageURL'] = $storage->get_image_url($this->_orig_image, 'full');
1675
- return $this->_cache['imageURL'];
1676
- case 'linktitle':
1677
- $this->_cache['linktitle'] = htmlspecialchars(stripslashes($this->__get('description')));
1678
- return $this->_cache['linktitle'];
1679
- case 'name':
1680
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1681
- $this->_cache['name'] = $gallery->name;
1682
- return $this->_cache['name'];
1683
- case 'pageid':
1684
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1685
- $this->_cache['pageid'] = $gallery->name;
1686
- return $this->_cache['pageid'];
1687
- case 'path':
1688
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1689
- $this->_cache['path'] = $gallery->name;
1690
- return $this->_cache['path'];
1691
- case 'permalink':
1692
- $this->_cache['permalink'] = $this->__get('imageURL');
1693
- return $this->_cache['permalink'];
1694
- case 'pid':
1695
- return $this->_orig_image_id;
1696
- case 'id_field':
1697
- $this->_cache['id_field'] = !empty($this->_orig_image->id_field) ? $this->_orig_image->id_field : 'pid';
1698
- return $this->_cache['id_field'];
1699
- case 'pidlink':
1700
- $application = C_Router::get_instance()->get_routed_app();
1701
- $controller = C_Display_Type_Controller::get_instance();
1702
- $this->_cache['pidlink'] = $controller->set_param_for($application->get_routed_url(TRUE), 'pid', $this->__get('image_slug'));
1703
- return $this->_cache['pidlink'];
1704
- case 'previewpic':
1705
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1706
- $this->_cache['previewpic'] = $gallery->name;
1707
- return $this->_cache['previewpic'];
1708
- case 'size':
1709
- $w = 0;
1710
- $h = 0;
1711
- if ($this->_displayed_gallery && isset($this->_displayed_gallery->display_settings)) {
1712
- $ds = $this->_displayed_gallery->display_settings;
1713
- if (isset($ds['override_thumbnail_settings']) && $ds['override_thumbnail_settings']) {
1714
- $w = $ds['thumbnail_width'];
1715
- $h = $ds['thumbnail_height'];
1716
  }
 
 
 
1717
  }
1718
- if (!$w || !$h) {
1719
- if (is_string($this->_orig_image->meta_data)) {
1720
- $this->_orig_image = C_NextGen_Serializable::unserialize($this->_orig_image->meta_data);
 
 
 
 
1721
  }
1722
- if (!isset($this->_orig_image->meta_data['thumbnail'])) {
1723
- $storage = $this->get_storage();
1724
- $storage->generate_thumbnail($this->_orig_image);
 
 
 
1725
  }
1726
- $w = $this->_orig_image->meta_data['thumbnail']['width'];
1727
- $h = $this->_orig_image->meta_data['thumbnail']['height'];
1728
  }
1729
- return "width='{$w}' height='{$h}'";
1730
- case 'slug':
1731
- $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
1732
- $this->_cache['slug'] = $gallery->name;
1733
- return $this->_cache['slug'];
1734
- case 'tags':
1735
- $this->_cache['tags'] = wp_get_object_terms($this->__get('id'), 'ngg_tag', 'fields=all');
1736
- return $this->_cache['tags'];
1737
- case 'thumbHTML':
1738
- $tmp = '<a href="' . $this->__get('imageURL') . '" title="' . htmlspecialchars(stripslashes($this->__get('description'))) . '" ' . $this->get_thumbcode($this->__get('name')) . '>' . '<img alt="' . $this->__get('alttext') . '" src="' . $this->thumbURL . '"/>' . '</a>';
1739
- $this->_cache['href'] = $tmp;
1740
- $this->_cache['thumbHTML'] = $tmp;
1741
- return $this->_cache['thumbHTML'];
1742
- case 'thumbPath':
1743
- $storage = $this->get_storage();
1744
- $this->_cache['thumbPath'] = $storage->get_image_abspath($this->_orig_image, 'thumbnail');
1745
- return $this->_cache['thumbPath'];
1746
- case 'thumbnailURL':
1747
- $storage = $this->get_storage();
1748
- $thumbnail_size_name = 'thumbnail';
1749
- if ($this->_displayed_gallery && isset($this->_displayed_gallery->display_settings)) {
1750
- $ds = $this->_displayed_gallery->display_settings;
1751
- if (isset($ds['override_thumbnail_settings']) && $ds['override_thumbnail_settings']) {
1752
- $dynthumbs = C_Component_Registry::get_instance()->get_utility('I_Dynamic_Thumbnails_Manager');
1753
- $dyn_params = array('width' => $ds['thumbnail_width'], 'height' => $ds['thumbnail_height']);
1754
- if ($ds['thumbnail_quality']) {
1755
- $dyn_params['quality'] = $ds['thumbnail_quality'];
1756
  }
1757
- if ($ds['thumbnail_crop']) {
1758
- $dyn_params['crop'] = TRUE;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1759
  }
1760
- if ($ds['thumbnail_watermark']) {
1761
- $dyn_params['watermark'] = TRUE;
 
 
 
 
 
 
 
 
 
 
 
 
1762
  }
1763
- $thumbnail_size_name = $dynthumbs->get_size_name($dyn_params);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1764
  }
1765
- }
1766
- $this->_cache['thumbnailURL'] = $storage->get_image_url($this->_orig_image, $thumbnail_size_name);
1767
- return $this->_cache['thumbnailURL'];
1768
- case 'thumbcode':
1769
- if ($this->_displayed_gallery && isset($this->_displayed_gallery->display_settings) && isset($this->_displayed_gallery->display_settings['use_imagebrowser_effect']) && $this->_displayed_gallery->display_settings['use_imagebrowser_effect'] && !empty($this->_orig_image->thumbcode)) {
1770
- $this->_cache['thumbcode'] = $this->_orig_image->thumbcode;
1771
  } else {
1772
- $this->_cache['thumbcode'] = $this->get_thumbcode($this->__get('name'));
 
1773
  }
1774
- return $this->_cache['thumbcode'];
1775
- case 'thumbURL':
1776
- return $this->__get('thumbnailURL');
1777
- case 'title':
1778
- $this->_cache['title'] = stripslashes($this->__get('name'));
1779
- return $this->_cache['title'];
1780
- case 'url':
1781
- $storage = $this->get_storage();
1782
- $this->_cache['url'] = $storage->get_image_url($this->_orig_image, 'full');
1783
- return $this->_cache['url'];
1784
- default:
1785
- return $this->_cache[$name];
 
 
 
 
 
 
 
1786
  }
 
1787
  }
1788
- // called on initial nggLegacy image at construction. not sure what to do with it now.
1789
- function construct_ngg_Image($gallery)
1790
- {
1791
- do_action_ref_array('ngg_get_image', array(&$this));
1792
- unset($this->tags);
1793
- }
1794
- /**
1795
- * Retrieves and caches an I_Settings_Manager instance
1796
- *
1797
- * @return mixed
1798
- */
1799
- function get_settings()
1800
  {
1801
- if (is_null($this->_settings)) {
1802
- $this->_settings = C_NextGen_Settings::get_instance();
 
 
 
 
 
1803
  }
1804
- return $this->_settings;
1805
  }
1806
- /**
1807
- * Retrieves and caches an I_Gallery_Storage instance
1808
- *
1809
- * @return mixed
1810
- */
1811
- function get_storage()
1812
  {
1813
- if (is_null($this->_storage)) {
1814
- $this->_storage = C_Gallery_Storage::get_instance();
 
 
 
1815
  }
1816
- return $this->_storage;
 
 
 
1817
  }
1818
  /**
1819
- * Retrieves I_Gallery_Mapper instance.
1820
- *
1821
- * @param int $gallery_id Gallery ID
1822
- * @return mixed
 
 
 
1823
  */
1824
- function get_gallery($gallery_id)
1825
  {
1826
- if (isset($this->container) && method_exists($this->container, 'get_gallery')) {
1827
- return $this->container->get_gallery($gallery_id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1828
  }
1829
- return C_Gallery_Mapper::get_instance()->find($gallery_id);
1830
  }
1831
  /**
1832
- * Retrieves I_Gallery_Mapper instance.
1833
- *
1834
- * @param int $gallery_id Gallery ID
1835
- * @return mixed
1836
  */
1837
- function get_legacy_gallery($gallery_id)
1838
  {
1839
- return C_Gallery_Mapper::get_instance()->find($gallery_id);
 
1840
  }
1841
  /**
1842
- * Get the thumbnail code (to add effects on thumbnail click)
1843
- *
1844
- * Applies the filter 'ngg_get_thumbcode'
1845
- * @param string $gallery_name (optional) Default = ''
1846
- * @return string
1847
  */
1848
- function get_thumbcode($gallery_name = '')
1849
  {
1850
- if (empty($this->_displayed_gallery)) {
1851
- $effect_code = C_NextGen_Settings::get_instance()->thumbCode;
1852
- $effect_code = str_replace('%GALLERY_ID%', $gallery_name, $effect_code);
1853
- $effect_code = str_replace('%GALLERY_NAME%', $gallery_name, $effect_code);
1854
- $retval = $effect_code;
1855
- } else {
1856
- $controller = C_Display_Type_Controller::get_instance();
1857
- $retval = $controller->get_effect_code($this->_displayed_gallery);
1858
- // This setting requires that we disable the effect code
1859
- $ds = $this->_displayed_gallery->display_settings;
1860
- if (isset($ds['use_imagebrowser_effect']) && $ds['use_imagebrowser_effect']) {
1861
- $retval = '';
1862
  }
 
 
1863
  }
1864
- $retval = apply_filters('ngg_get_thumbcode', $retval, $this);
1865
- // ensure some additional data- fields are added; provides Pro-Lightbox compatibility
1866
- $retval .= ' data-image-id="' . $this->__get('id') . '"';
1867
- $retval .= ' data-src="' . $this->__get('imageURL') . '"';
1868
- $retval .= ' data-thumbnail="' . $this->__get('thumbnailURL') . '"';
1869
- $retval .= ' data-title="' . esc_attr($this->__get('alttext')) . '"';
1870
- $retval .= ' data-description="' . esc_attr($this->__get('description')) . '"';
1871
- $this->_cache['thumbcode'] = $retval;
1872
  return $retval;
1873
  }
1874
  /**
1875
- * For compatibility support
1876
  *
1877
- * @return mixed
 
 
 
1878
  */
1879
- function get_href_link()
1880
  {
1881
- return $this->__get('imageHTML');
1882
  }
1883
  /**
1884
- * For compatibility support
1885
- *
1886
- * @return mixed
1887
  */
1888
- function get_href_thumb_link()
1889
  {
1890
- return $this->__get('thumbHTML');
1891
  }
1892
  /**
1893
- * Function exists for legacy support but has been gutted to not do anything
1894
- *
1895
- * @param string|int $width (optional) Default = ''
1896
- * @param string|int $height (optional) Default = ''
1897
- * @param string $mode could be watermark | web20 | crop
1898
- * @return bool|string The url for the image or false if failed
1899
  */
1900
- function cached_singlepic_file($width = '', $height = '', $mode = '')
1901
  {
1902
- $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
1903
- $storage = $this->get_storage();
1904
- // determine what to do with 'mode'
1905
- $display_reflection = FALSE;
1906
- $display_watermark = FALSE;
1907
- if (!is_array($mode)) {
1908
- $mode = explode(',', $mode);
1909
- }
1910
- if (in_array('web20', $mode)) {
1911
- $display_reflection = TRUE;
1912
- }
1913
- if (in_array('watermark', $mode)) {
1914
- $display_watermark = TRUE;
1915
- }
1916
- // and go for it
1917
- $params = array('width' => $width, 'height' => $height, 'watermark' => $display_watermark, 'reflection' => $display_reflection);
1918
- return $storage->get_image_url((object) $this->_cache, $dynthumbs->get_size_name($params));
1919
  }
1920
  /**
1921
- * Get the tags associated to this image
 
 
1922
  */
1923
- function get_tags()
1924
  {
1925
- return $this->__get('tags');
1926
  }
1927
  /**
1928
- * Get the permalink to the image
1929
  *
1930
- * TODO: Get a permalink to a page presenting the image
 
1931
  */
1932
- function get_permalink()
1933
  {
1934
- return $this->__get('permalink');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1935
  }
1936
  /**
1937
- * Returns the _cache array; used by nggImage
1938
- * @return array
 
 
1939
  */
1940
- function _get_image()
1941
- {
1942
- return $this->_cache;
1943
- }
1944
- }
1945
- class C_Image_Wrapper_Collection implements ArrayAccess
1946
- {
1947
- public $container = array();
1948
- public $galleries = array();
1949
- public function offsetExists($offset)
1950
  {
1951
- return isset($this->container[$offset]);
 
 
 
 
1952
  }
1953
- public function offsetGet($offset)
1954
  {
1955
- return isset($this->container[$offset]) ? $this->container[$offset] : null;
 
 
 
 
 
1956
  }
1957
- public function offsetSet($offset, $value)
 
 
 
 
 
 
1958
  {
1959
- if (is_object($value)) {
1960
- $value->container = $this;
 
 
 
1961
  }
1962
- if (is_null($offset)) {
1963
- $this->container[] = $value;
1964
- } else {
1965
- $this->container[$offset] = $value;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1966
  }
 
1967
  }
1968
- public function offsetUnset($offset)
1969
  {
1970
- unset($this->container[$offset]);
 
 
 
 
1971
  }
1972
  /**
1973
- * Retrieves and caches an I_Gallery_Mapper instance for this gallery id
1974
  *
1975
- * @param int $gallery_id Gallery ID
1976
- * @return mixed
 
1977
  */
1978
- public function get_gallery($gallery_id)
1979
  {
1980
- if (!isset($this->galleries[$gallery_id]) || is_null($this->galleries[$gallery_id])) {
1981
- $this->galleries[$gallery_id] = C_Gallery_Mapper::get_instance();
 
 
1982
  }
1983
- return $this->galleries[$gallery_id];
1984
- }
1985
- }
1986
- class C_NextGen_Data_Installer extends C_NggLegacy_Installer
1987
- {
1988
- function get_registry()
1989
- {
1990
- return C_Component_Registry::get_instance();
1991
- }
1992
- function install()
1993
- {
1994
- $this->remove_table_extra_options();
1995
- }
1996
- function remove_table_extra_options()
1997
- {
1998
- global $wpdb;
1999
- $likes = array("option_name LIKE '%ngg_gallery%'", "option_name LIKE '%ngg_pictures%'", "option_name LIKE '%ngg_album%'");
2000
- $sql = "DELETE FROM {$wpdb->options} WHERE " . implode(" OR ", $likes);
2001
- $wpdb->query($sql);
 
 
 
 
 
 
 
 
 
 
2002
  }
2003
- function uninstall($hard = FALSE)
2004
  {
2005
- if ($hard) {
2006
- /* Yes: this is commented twice.
2007
- // TODO for now never delete galleries/albums/content
2008
- # $mappers = array(
2009
- # $this->get_registry()->get_utility('I_Album_Mapper'),
2010
- # $this->get_registry()->get_utility('I_Gallery_Mapper'),
2011
- # $this->get_registry()->get_utility('I_Image_Mapper'),
2012
- # );
2013
-
2014
- # foreach ($mappers as $mapper) {
2015
- # $mapper->delete()->run_query();
2016
- # }
2017
-
2018
- # // Remove ngg tags
2019
- # global $wpdb;
2020
- # $wpdb->query("DELETE FROM {$wpdb->terms} WHERE term_id IN (SELECT term_id FROM {$wpdb->term_taxonomy} WHERE taxonomy='ngg_tag')");
2021
- # $wpdb->query("DELETE FROM {$wpdb->term_taxonomy} WHERE taxonomy='ngg_tag'");
2022
- */
2023
- }
2024
  }
2025
- }
2026
- class C_NextGen_Metadata extends C_Component
2027
- {
2028
- // Image data
2029
- public $image = '';
2030
- // The image object
2031
- public $file_path = '';
2032
- // Path to the image file
2033
- public $size = FALSE;
2034
- // The image size
2035
- public $exif_data = FALSE;
2036
- // EXIF data array
2037
- public $iptc_data = FALSE;
2038
- // IPTC data array
2039
- public $xmp_data = FALSE;
2040
- // XMP data array
2041
- // Filtered Data
2042
- public $exif_array = FALSE;
2043
- // EXIF data array
2044
- public $iptc_array = FALSE;
2045
- // IPTC data array
2046
- public $xmp_array = FALSE;
2047
- // XMP data array
2048
- public $sanitize = FALSE;
2049
- // sanitize meta data on request
2050
  /**
2051
- * Class constructor
2052
- *
2053
- * @param int $image Image ID
2054
- * @param bool $onlyEXIF TRUE = will parse only EXIF data
2055
- * @return bool FALSE if the file does not exist or metadat could not be read
2056
  */
2057
- public function __construct($image, $onlyEXIF = FALSE)
2058
  {
 
2059
  if (is_numeric($image)) {
2060
- $image = C_Image_Mapper::get_instance()->find($image);
2061
- }
2062
- $this->image = apply_filters('ngg_find_image_meta', $image);
2063
- $this->file_path = C_Gallery_Storage::get_instance()->get_image_abspath($this->image);
2064
- if (!@file_exists($this->file_path)) {
2065
- return FALSE;
2066
  }
2067
- $this->size = @getimagesize($this->file_path, $metadata);
2068
- if ($this->size && is_array($metadata)) {
2069
- // get exif - data
2070
- if (is_callable('exif_read_data')) {
2071
- $this->exif_data = @exif_read_data($this->file_path, NULL, TRUE);
2072
  }
2073
- // stop here if we didn't need other meta data
2074
- if ($onlyEXIF) {
2075
- return TRUE;
2076
  }
2077
- // get the iptc data - should be in APP13
2078
- if (is_callable('iptcparse') && isset($metadata['APP13'])) {
2079
- $this->iptc_data = @iptcparse($metadata['APP13']);
 
 
 
 
 
 
2080
  }
2081
- // get the xmp data in a XML format
2082
- if (is_callable('xml_parser_create')) {
2083
- $this->xmp_data = $this->extract_XMP($this->file_path);
2084
  }
2085
- return TRUE;
 
 
 
 
 
 
 
2086
  }
2087
- return FALSE;
2088
  }
2089
- /**
2090
- * return the saved meta data from the database
2091
- *
2092
- * @since 1.4.0
2093
- * @param string $object (optional)
2094
- * @return array|mixed return either the complete array or the single object
2095
- */
2096
- function get_saved_meta($object = false)
2097
  {
2098
- $meta = $this->image->meta_data;
2099
- // Check if we already import the meta data to the database
2100
- if (!is_array($meta) || !isset($meta['saved']) || $meta['saved'] !== TRUE) {
2101
- return false;
2102
- }
2103
- // return one element if requested
2104
- if ($object) {
2105
- return $meta[$object];
2106
- }
2107
- //removed saved parameter we don't need that to show
2108
- unset($meta['saved']);
2109
- // and remove empty tags or arrays
2110
- foreach ($meta as $key => $value) {
2111
- if (empty($value) or is_array($value)) {
2112
- unset($meta[$key]);
2113
  }
2114
  }
2115
- // on request sanitize the output
2116
- if ($this->sanitize == true) {
2117
- array_walk($meta, 'esc_html');
 
 
 
 
 
 
 
 
 
 
2118
  }
2119
- return $meta;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2120
  }
2121
  /**
2122
- * nggMeta::get_EXIF()
2123
- * See also http://trac.wordpress.org/changeset/6313
2124
- *
2125
- * @return bool|array
2126
  */
2127
- function get_EXIF($object = false)
2128
  {
2129
- if (!$this->exif_data) {
2130
- return false;
 
2131
  }
2132
- if (!is_array($this->exif_array)) {
2133
- $meta = array();
2134
- if (isset($this->exif_data['EXIF'])) {
2135
- $exif = $this->exif_data['EXIF'];
2136
- if (!empty($exif['FNumber'])) {
2137
- $meta['aperture'] = 'F ' . round($this->exif_frac2dec($exif['FNumber']), 2);
 
2138
  }
2139
- if (!empty($exif['Model'])) {
2140
- $meta['camera'] = trim($exif['Model']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2141
  }
2142
- if (!empty($exif['DateTimeDigitized'])) {
2143
- $meta['created_timestamp'] = $this->exif_date2ts($exif['DateTimeDigitized']);
 
 
 
 
 
 
 
 
 
 
2144
  } else {
2145
- if (!empty($exif['DateTimeOriginal'])) {
2146
- $meta['created_timestamp'] = $this->exif_date2ts($exif['DateTimeOriginal']);
 
 
 
 
 
 
 
 
 
2147
  } else {
2148
- if (!empty($exif['FileDateTime'])) {
2149
- $meta['created_timestamp'] = $this->exif_date2ts($exif['FileDateTime']);
 
 
 
 
 
 
2150
  }
2151
  }
2152
  }
2153
- if (!empty($exif['FocalLength'])) {
2154
- $meta['focal_length'] = $this->exif_frac2dec($exif['FocalLength']) . __(' mm', 'nggallery');
2155
- }
2156
- if (!empty($exif['ISOSpeedRatings'])) {
2157
- $meta['iso'] = $exif['ISOSpeedRatings'];
2158
- }
2159
- if (!empty($exif['ExposureTime'])) {
2160
- $meta['shutter_speed'] = $this->exif_frac2dec($exif['ExposureTime']);
2161
- $meta['shutter_speed'] = ($meta['shutter_speed'] > 0.0 and $meta['shutter_speed'] < 1.0) ? '1/' . round(1 / $meta['shutter_speed'], -1) : $meta['shutter_speed'];
2162
- $meta['shutter_speed'] .= __(' sec', 'nggallery');
2163
- }
2164
- //Bit 0 indicates the flash firing status
2165
- if (!empty($exif['Flash'])) {
2166
- $meta['flash'] = $exif['Flash'] & 1 ? __('Fired', 'nggallery') : __('Not fired', ' nggallery');
2167
- }
2168
- }
2169
- // additional information
2170
- if (isset($this->exif_data['IFD0'])) {
2171
- $exif = $this->exif_data['IFD0'];
2172
- if (!empty($exif['Model'])) {
2173
- $meta['camera'] = $exif['Model'];
2174
- }
2175
- if (!empty($exif['Make'])) {
2176
- $meta['make'] = $exif['Make'];
2177
- }
2178
- if (!empty($exif['ImageDescription'])) {
2179
- $meta['title'] = $this->utf8_encode($exif['ImageDescription']);
2180
- }
2181
- if (!empty($exif['Orientation'])) {
2182
- $meta['Orientation'] = $exif['Orientation'];
2183
- }
2184
  }
2185
- // this is done by Windows
2186
- if (isset($this->exif_data['WINXP'])) {
2187
- $exif = $this->exif_data['WINXP'];
2188
- if (!empty($exif['Title']) && empty($meta['title'])) {
2189
- $meta['title'] = $this->utf8_encode($exif['Title']);
2190
- }
2191
- if (!empty($exif['Author'])) {
2192
- $meta['author'] = $this->utf8_encode($exif['Author']);
2193
  }
2194
- if (!empty($exif['Keywords'])) {
2195
- $meta['keywords'] = $this->utf8_encode($exif['Keywords']);
 
 
 
 
 
 
2196
  }
2197
- if (!empty($exif['Subject'])) {
2198
- $meta['subject'] = $this->utf8_encode($exif['Subject']);
 
2199
  }
2200
- if (!empty($exif['Comments'])) {
2201
- $meta['caption'] = $this->utf8_encode($exif['Comments']);
2202
  }
2203
  }
2204
- $this->exif_array = $meta;
2205
- }
2206
- // return one element if requested
2207
- if ($object == true) {
2208
- $value = isset($this->exif_array[$object]) ? $this->exif_array[$object] : false;
2209
- return $value;
2210
- }
2211
- // on request sanitize the output
2212
- if ($this->sanitize == true) {
2213
- array_walk($this->exif_array, 'esc_html');
2214
  }
2215
- return $this->exif_array;
2216
  }
2217
- // convert a fraction string to a decimal
2218
- function exif_frac2dec($str)
 
 
 
 
2219
  {
2220
- @(list($n, $d) = explode('/', $str));
2221
- if (!empty($d)) {
2222
- return $n / $d;
2223
- }
2224
- return $str;
2225
  }
2226
- // convert the exif date format to a unix timestamp
2227
- function exif_date2ts($str)
 
 
 
 
2228
  {
2229
- $retval = is_numeric($str) ? $str : @strtotime($str);
2230
- if (!$retval && $str) {
2231
- @(list($date, $time) = explode(' ', trim($str)));
2232
- @(list($y, $m, $d) = explode(':', $date));
2233
- $retval = strtotime("{$y}-{$m}-{$d} {$time}");
2234
- }
2235
- return $retval;
2236
  }
2237
  /**
2238
- * nggMeta::readIPTC() - IPTC Data Information for EXIF Display
2239
- *
2240
- * @param object $object (optional)
2241
- * @return null|bool|array
2242
  */
2243
- function get_IPTC($object = false)
2244
  {
2245
- if (!$this->iptc_data) {
2246
- return false;
2247
- }
2248
- if (!is_array($this->iptc_array)) {
2249
- // --------- Set up Array Functions --------- //
2250
- $iptcTags = array("2#005" => 'title', "2#007" => 'status', "2#012" => 'subject', "2#015" => 'category', "2#025" => 'keywords', "2#055" => 'created_date', "2#060" => 'created_time', "2#080" => 'author', "2#085" => 'position', "2#090" => 'city', "2#092" => 'location', "2#095" => 'state', "2#100" => 'country_code', "2#101" => 'country', "2#105" => 'headline', "2#110" => 'credit', "2#115" => 'source', "2#116" => 'copyright', "2#118" => 'contact', "2#120" => 'caption');
2251
- $meta = array();
2252
- foreach ($iptcTags as $key => $value) {
2253
- if (isset($this->iptc_data[$key])) {
2254
- $meta[$value] = trim($this->utf8_encode(implode(", ", $this->iptc_data[$key])));
2255
- }
2256
- }
2257
- $this->iptc_array = $meta;
2258
- }
2259
- // return one element if requested
2260
- if ($object) {
2261
- return isset($this->iptc_array[$object]) ? $this->iptc_array[$object] : NULL;
2262
  }
2263
- // on request sanitize the output
2264
- if ($this->sanitize == true) {
2265
- array_walk($this->iptc_array, 'esc_html');
2266
  }
2267
- return $this->iptc_array;
 
2268
  }
2269
  /**
2270
- * nggMeta::extract_XMP()
2271
- * get XMP DATA
2272
- * code by Pekka Saarinen http://photography-on-the.net
2273
- *
2274
- * @param mixed $filename
2275
- * @return bool|string
2276
  */
2277
- function extract_XMP($filename)
2278
  {
2279
- //TODO:Require a lot of memory, could be better
2280
- ob_start();
2281
- @readfile($filename);
2282
- $source = ob_get_contents();
2283
- ob_end_clean();
2284
- $start = strpos($source, "<x:xmpmeta");
2285
- $end = strpos($source, "</x:xmpmeta>");
2286
- if (!$start === false && !$end === false) {
2287
- $lenght = $end - $start;
2288
- $xmp_data = substr($source, $start, $lenght + 12);
2289
- unset($source);
2290
- return $xmp_data;
2291
- }
2292
- unset($source);
2293
- return false;
2294
  }
2295
  /**
2296
- * nggMeta::get_XMP()
2297
- *
2298
- * @package Taken from http://php.net/manual/en/function.xml-parse-into-struct.php
2299
- * @author Alf Marius Foss Olsen & Alex Rabe
2300
- * @return bool|array
2301
  *
 
 
 
2302
  */
2303
- function get_XMP($object = false)
2304
  {
2305
- if (!$this->xmp_data) {
2306
- return false;
 
 
 
2307
  }
2308
- if (!is_array($this->xmp_array)) {
2309
- $parser = xml_parser_create();
2310
- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2311
- // Dont mess with my cAsE sEtTings
2312
- xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2313
- // Dont bother with empty info
2314
- xml_parse_into_struct($parser, $this->xmp_data, $values);
2315
- xml_parser_free($parser);
2316
- $xmlarray = array();
2317
- // The XML array
2318
- $this->xmp_array = array();
2319
- // The returned array
2320
- $stack = array();
2321
- // tmp array used for stacking
2322
- $list_array = array();
2323
- // tmp array for list elements
2324
- $list_element = false;
2325
- // rdf:li indicator
2326
- foreach ($values as $val) {
2327
- if ($val['type'] == "open") {
2328
- array_push($stack, $val['tag']);
2329
- } elseif ($val['type'] == "close") {
2330
- // reset the compared stack
2331
- if ($list_element == false) {
2332
- array_pop($stack);
2333
- }
2334
- // reset the rdf:li indicator & array
2335
- $list_element = false;
2336
- $list_array = array();
2337
- } elseif ($val['type'] == "complete") {
2338
- if ($val['tag'] == "rdf:li") {
2339
- // first go one element back
2340
- if ($list_element == false) {
2341
- array_pop($stack);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2342
  }
2343
- $list_element = true;
2344
- // do not parse empty tags
2345
- if (empty($val['value'])) {
 
 
 
 
 
 
 
2346
  continue;
2347
  }
2348
- // save it in our temp array
2349
- $list_array[] = $val['value'];
2350
- // in the case it's a list element we seralize it
2351
- $value = implode(",", $list_array);
2352
- $this->setArrayValue($xmlarray, $stack, $value);
2353
- } else {
2354
- array_push($stack, $val['tag']);
2355
- // do not parse empty tags
2356
- if (!empty($val['value'])) {
2357
- $this->setArrayValue($xmlarray, $stack, $val['value']);
2358
  }
2359
- array_pop($stack);
2360
- }
2361
- }
2362
- }
2363
- // foreach
2364
- // don't parse a empty array
2365
- if (empty($xmlarray) || empty($xmlarray['x:xmpmeta'])) {
2366
- return false;
2367
- }
2368
- // cut off the useless tags
2369
- $xmlarray = $xmlarray['x:xmpmeta']['rdf:RDF']['rdf:Description'];
2370
- // --------- Some values from the XMP format--------- //
2371
- $xmpTags = array('xap:CreateDate' => 'created_timestamp', 'xap:ModifyDate' => 'last_modfied', 'xap:CreatorTool' => 'tool', 'dc:format' => 'format', 'dc:title' => 'title', 'dc:creator' => 'author', 'dc:subject' => 'keywords', 'dc:description' => 'caption', 'photoshop:AuthorsPosition' => 'position', 'photoshop:City' => 'city', 'photoshop:Country' => 'country');
2372
- foreach ($xmpTags as $key => $value) {
2373
- // if the kex exist
2374
- if (isset($xmlarray[$key])) {
2375
- switch ($key) {
2376
- case 'xap:CreateDate':
2377
- case 'xap:ModifyDate':
2378
- $this->xmp_array[$value] = strtotime($xmlarray[$key]);
2379
- break;
2380
- default:
2381
- $this->xmp_array[$value] = $xmlarray[$key];
2382
  }
 
 
2383
  }
2384
  }
2385
  }
2386
- // return one element if requested
2387
- if ($object != false) {
2388
- return isset($this->xmp_array[$object]) ? $this->xmp_array[$object] : false;
2389
- }
2390
- // on request sanitize the output
2391
- if ($this->sanitize == true) {
2392
- array_walk($this->xmp_array, 'esc_html');
2393
- }
2394
- return $this->xmp_array;
2395
  }
2396
- function setArrayValue(&$array, $stack, $value)
 
 
 
 
 
 
2397
  {
2398
- if ($stack) {
2399
- $key = array_shift($stack);
2400
- $this->setArrayValue($array[$key], $stack, $value);
2401
- return $array;
2402
- } else {
2403
- $array = $value;
2404
  }
2405
- return $array;
2406
  }
2407
  /**
2408
- * nggMeta::get_META() - return a meta value form the available list
2409
- *
2410
- * @param string $object
2411
- * @return mixed $value
2412
  */
2413
- function get_META($object = false)
2414
  {
2415
- // defined order first look into database, then XMP, IPTC and EXIF.
2416
- if ($value = $this->get_saved_meta($object)) {
2417
- return $value;
2418
- }
2419
- if ($value = $this->get_XMP($object)) {
2420
- return $value;
 
 
 
 
 
 
 
 
 
2421
  }
2422
- if ($object == 'created_timestamp' && ($d = $this->get_IPTC('created_date')) && ($t = $this->get_IPTC('created_time'))) {
2423
- return $this->exif_date2ts($d . ' ' . $t);
 
 
 
 
 
 
 
2424
  }
2425
- if ($value = $this->get_IPTC($object)) {
2426
- return $value;
 
 
 
 
 
2427
  }
2428
- if ($value = $this->get_EXIF($object)) {
2429
- return $value;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2430
  }
2431
- // nothing found ?
2432
- return false;
2433
  }
2434
  /**
2435
- * nggMeta::i8n_name() - localize the tag name
2436
  *
2437
- * @param mixed $key
2438
- * @return string Translated $key
2439
  */
2440
- function i18n_name($key)
2441
  {
2442
- $tagnames = array('aperture' => __('Aperture', 'nggallery'), 'credit' => __('Credit', 'nggallery'), 'camera' => __('Camera', 'nggallery'), 'caption' => __('Caption', 'nggallery'), 'created_timestamp' => __('Date/Time', 'nggallery'), 'copyright' => __('Copyright', 'nggallery'), 'focal_length' => __('Focal length', 'nggallery'), 'iso' => __('ISO', 'nggallery'), 'shutter_speed' => __('Shutter speed', 'nggallery'), 'title' => __('Title', 'nggallery'), 'author' => __('Author', 'nggallery'), 'tags' => __('Tags', 'nggallery'), 'subject' => __('Subject', 'nggallery'), 'make' => __('Make', 'nggallery'), 'status' => __('Edit Status', 'nggallery'), 'category' => __('Category', 'nggallery'), 'keywords' => __('Keywords', 'nggallery'), 'created_date' => __('Date Created', 'nggallery'), 'created_time' => __('Time Created', 'nggallery'), 'position' => __('Author Position', 'nggallery'), 'city' => __('City', 'nggallery'), 'location' => __('Location', 'nggallery'), 'state' => __('Province/State', 'nggallery'), 'country_code' => __('Country code', 'nggallery'), 'country' => __('Country', 'nggallery'), 'headline' => __('Headline', 'nggallery'), 'credit' => __('Credit', 'nggallery'), 'source' => __('Source', 'nggallery'), 'copyright' => __('Copyright Notice', 'nggallery'), 'contact' => __('Contact', 'nggallery'), 'last_modfied' => __('Last modified', 'nggallery'), 'tool' => __('Program tool', 'nggallery'), 'format' => __('Format', 'nggallery'), 'width' => __('Image Width', 'nggallery'), 'height' => __('Image Height', 'nggallery'), 'flash' => __('Flash', 'nggallery'));
2443
- if (isset($tagnames[$key])) {
2444
- $key = $tagnames[$key];
2445
  }
2446
- return $key;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2447
  }
2448
  /**
2449
- * Return the Timestamp from the image , if possible it's read from exif data
2450
- * @return string
 
 
2451
  */
2452
- function get_date_time()
2453
  {
2454
- $date = time();
2455
- // Try getting the created_timestamp field
2456
- $date = $this->exif_date2ts($this->get_META('created_timestamp'));
2457
- if (!$date) {
2458
- $image_path = C_Gallery_Storage::get_instance()->get_backup_abspath($this->image);
2459
- $date = @filectime($image_path);
2460
  }
2461
- // Failback
2462
- if (!$date) {
2463
- $date = time();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2464
  }
2465
- // Return the MySQL format
2466
- $date_time = date('Y-m-d H:i:s', $date);
2467
- return $date_time;
2468
  }
2469
  /**
2470
- * This function return the most common metadata, via a filter we can add more
2471
- * Reason : GD manipulation removes that options
2472
  *
2473
- * @since V1.4.0
2474
- * @return array|false
2475
  */
2476
- function get_common_meta()
2477
  {
2478
- global $wpdb;
2479
- $meta = array('aperture' => 0, 'credit' => '', 'camera' => '', 'caption' => '', 'created_timestamp' => 0, 'copyright' => '', 'focal_length' => 0, 'iso' => 0, 'shutter_speed' => 0, 'flash' => 0, 'title' => '', 'keywords' => '');
2480
- $meta = apply_filters('ngg_read_image_metadata', $meta);
2481
- // meta should be still an array
2482
- if (!is_array($meta)) {
2483
- return false;
2484
  }
2485
- foreach ($meta as $key => $value) {
2486
- $meta[$key] = $this->get_META($key);
2487
  }
2488
- //let's add now the size of the image
2489
- $meta['width'] = $this->size[0];
2490
- $meta['height'] = $this->size[1];
2491
- return $meta;
2492
  }
2493
  /**
2494
- * If needed sanitize each value before output
2495
  *
2496
- * @return void
 
2497
  */
2498
- function sanitize()
2499
  {
2500
- $this->sanitize = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
2501
  }
2502
  /**
2503
- * Wrapper to utf8_encode() that avoids double encoding
2504
- *
2505
- * Regex adapted from http://www.w3.org/International/questions/qa-forms-utf-8.en.php
2506
- * to determine if the given string is already UTF-8. mb_detect_encoding() is not
2507
- * always available and is limited in accuracy
2508
- *
2509
- * @param string $str
2510
- * @return string
2511
  */
2512
- function utf8_encode($str)
2513
  {
2514
- $is_utf8 = preg_match('%^(?:
2515
- [\\x09\\x0A\\x0D\\x20-\\x7E] # ASCII
2516
- | [\\xC2-\\xDF][\\x80-\\xBF] # non-overlong 2-byte
2517
- | \\xE0[\\xA0-\\xBF][\\x80-\\xBF] # excluding overlongs
2518
- | [\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2} # straight 3-byte
2519
- | \\xED[\\x80-\\x9F][\\x80-\\xBF] # excluding surrogates
2520
- | \\xF0[\\x90-\\xBF][\\x80-\\xBF]{2} # planes 1-3
2521
- | [\\xF1-\\xF3][\\x80-\\xBF]{3} # planes 4-15
2522
- | \\xF4[\\x80-\\x8F][\\x80-\\xBF]{2} # plane 16
2523
- )*$%xs', $str);
2524
- if (!$is_utf8) {
2525
- utf8_encode($str);
2526
  }
2527
- return $str;
 
 
 
 
 
 
 
 
 
 
2528
  }
2529
- }
2530
- /**
2531
- * gd.thumbnail.inc.php
2532
- *
2533
- * @author Ian Selby (ian@gen-x-design.com)
2534
- * @copyright Copyright 2006-2011
2535
- * @version 1.3.0 (based on 1.1.3)
2536
- * @modded by Alex Rabe
2537
- *
2538
- */
2539
- /**
2540
- * PHP class for dynamically resizing, cropping, and rotating images for thumbnail purposes and either displaying them on-the-fly or saving them.
2541
- *
2542
- */
2543
- class C_NggLegacy_Thumbnail
2544
- {
2545
- /**
2546
- * Error message to display, if any
2547
- *
2548
- * @var string
2549
- */
2550
- var $errmsg;
2551
- /**
2552
- * Whether or not there is an error
2553
- *
2554
- * @var boolean
2555
- */
2556
- var $error;
2557
- /**
2558
- * Format of the image file
2559
- *
2560
- * @var string
2561
- */
2562
- var $format;
2563
- /**
2564
- * File name and path of the image file
2565
- *
2566
- * @var string
2567
- */
2568
- var $fileName;
2569
- /**
2570
- * Current dimensions of working image
2571
- *
2572
- * @var array
2573
- */
2574
- var $currentDimensions;
2575
- /**
2576
- * New dimensions of working image
2577
- *
2578
- * @var array
2579
- */
2580
- var $newDimensions;
2581
- /**
2582
- * Image resource for newly manipulated image
2583
- *
2584
- * @var resource
2585
- * @access private
2586
- */
2587
- var $newImage;
2588
- /**
2589
- * Image resource for image before previous manipulation
2590
- *
2591
- * @var resource
2592
- * @access private
2593
- */
2594
- var $oldImage;
2595
- /**
2596
- * Image resource for image being currently manipulated
2597
- *
2598
- * @var resource
2599
- * @access private
2600
- */
2601
- var $workingImage;
2602
- /**
2603
- * Percentage to resize image by
2604
- *
2605
- * @var int
2606
- * @access private
2607
- */
2608
- var $percent;
2609
- /**
2610
- * Maximum width of image during resize
2611
- *
2612
- * @var int
2613
- * @access private
2614
- */
2615
- var $maxWidth;
2616
- /**
2617
- * Maximum height of image during resize
2618
- *
2619
- * @var int
2620
- * @access private
2621
- */
2622
- var $maxHeight;
2623
- /**
2624
- * Image for Watermark
2625
- *
2626
- * @var string
2627
- *
2628
- */
2629
- var $watermarkImgPath;
2630
- /**
2631
- * Text for Watermark
2632
- *
2633
- * @var string
2634
- *
2635
- */
2636
- var $watermarkText;
2637
  /**
2638
- * Image Resource ID for Watermark
2639
- *
2640
- * @var string
2641
- *
2642
  */
2643
- function __construct($fileName, $no_ErrorImage = false)
2644
  {
2645
- //make sure the GD library is installed
2646
- if (!function_exists("gd_info")) {
2647
- echo 'You do not have the GD Library installed. This class requires the GD library to function properly.' . "\n";
2648
- echo 'visit http://us2.php.net/manual/en/ref.image.php for more information';
2649
- throw new E_No_Image_Library_Exception();
2650
- }
2651
- //initialize variables
2652
- $this->errmsg = '';
2653
- $this->error = false;
2654
- $this->currentDimensions = array();
2655
- $this->newDimensions = array();
2656
- $this->fileName = $fileName;
2657
- $this->percent = 100;
2658
- $this->maxWidth = 0;
2659
- $this->maxHeight = 0;
2660
- $this->watermarkImgPath = '';
2661
- $this->watermarkText = '';
2662
- //check to see if file exists
2663
- if (!@file_exists($this->fileName)) {
2664
- $this->errmsg = 'File not found';
2665
- $this->error = true;
2666
- } elseif (!is_readable($this->fileName)) {
2667
- $this->errmsg = 'File is not readable';
2668
- $this->error = true;
2669
- }
2670
- $image_size = null;
2671
- //if there are no errors, determine the file format
2672
- if ($this->error == false) {
2673
- // set_time_limit(30);
2674
- @ini_set('memory_limit', -1);
2675
- $image_size = @getimagesize($this->fileName);
2676
- if (isset($image_size) && is_array($image_size)) {
2677
- $extensions = array('1' => 'GIF', '2' => 'JPG', '3' => 'PNG');
2678
- $extension = array_key_exists($image_size[2], $extensions) ? $extensions[$image_size[2]] : '';
2679
- if ($extension) {
2680
- $this->format = $extension;
2681
- } else {
2682
- $this->errmsg = 'Unknown file format';
2683
- $this->error = true;
2684
- }
2685
- } else {
2686
- $this->errmsg = 'File is not an image';
2687
- $this->error = true;
2688
- }
2689
- }
2690
- // increase memory-limit if possible, GD needs this for large images
2691
- if (!extension_loaded('suhosin')) {
2692
- @ini_set('memory_limit', '512M');
2693
  }
2694
- if ($this->error == false) {
2695
- // Check memory consumption if file exists
2696
- $this->checkMemoryForImage($this->fileName);
 
 
 
 
 
 
 
 
2697
  }
2698
- //initialize resources if no errors
2699
- if ($this->error == false) {
2700
- $img_err = null;
2701
- switch ($this->format) {
2702
- case 'GIF':
2703
- if (function_exists('ImageCreateFromGif')) {
2704
- $this->oldImage = @ImageCreateFromGif($this->fileName);
2705
- } else {
2706
- $img_err = __('Support for GIF format is missing.', 'nggallery');
2707
- }
2708
- break;
2709
- case 'JPG':
2710
- if (function_exists('ImageCreateFromJpeg')) {
2711
- $this->oldImage = @ImageCreateFromJpeg($this->fileName);
2712
- } else {
2713
- $img_err = __('Support for JPEG format is missing.', 'nggallery');
2714
- }
2715
- break;
2716
- case 'PNG':
2717
- if (function_exists('ImageCreateFromPng')) {
2718
- $this->oldImage = @ImageCreateFromPng($this->fileName);
2719
- } else {
2720
- $img_err = __('Support for PNG format is missing.', 'nggallery');
2721
  }
2722
- break;
2723
- }
2724
- if (!$this->oldImage) {
2725
- if ($img_err == null) {
2726
- $img_err = __('Check memory limit', 'nggallery');
2727
  }
2728
- $this->errmsg = sprintf(__('Create Image failed. %1$s', 'nggallery'), $img_err);
2729
- $this->error = true;
2730
- } else {
2731
- $this->currentDimensions = array('width' => $image_size[0], 'height' => $image_size[1]);
2732
- $this->newImage = $this->oldImage;
2733
  }
2734
  }
2735
- if ($this->error == true) {
2736
- if (!$no_ErrorImage) {
2737
- $this->showErrorImage();
 
 
 
 
 
 
 
2738
  }
2739
- return;
2740
  }
 
2741
  }
2742
- /**
2743
- * Calculate the memory limit
2744
- * @param string $filename
2745
- *
2746
- */
2747
- function checkMemoryForImage($filename)
2748
  {
2749
- $imageInfo = getimagesize($filename);
2750
- switch ($this->format) {
2751
- case 'GIF':
2752
- // measured factor 1 is better
2753
- $CHANNEL = 1;
2754
- break;
2755
- case 'JPG':
2756
- $CHANNEL = $imageInfo['channels'];
2757
- break;
2758
- case 'PNG':
2759
- // didn't get the channel for png
2760
- $CHANNEL = 3;
2761
- break;
2762
  }
2763
- $bits = !empty($imageInfo['bits']) ? $imageInfo['bits'] : 32;
2764
- // imgInfo[bits] is not always available
2765
- return $this->checkMemoryForData($imageInfo[0], $imageInfo[1], $CHANNEL, $bits);
2766
  }
2767
- function checkMemoryForData($width, $height, $channels = null, $bits = null)
2768
  {
2769
- $imageInfo = getimagesize($this->fileName);
2770
- if ($channels == null) {
2771
- switch ($this->format) {
2772
- case 'GIF':
2773
- // measured factor 1 is better
2774
- $channels = 1;
2775
- break;
2776
- case 'JPG':
2777
- $channels = $imageInfo['channels'];
2778
- break;
2779
- case 'PNG':
2780
- // didn't get the channel for png
2781
- $channels = 3;
2782
- break;
2783
- }
2784
  }
2785
- if ($bits == null) {
2786
- $bits = !empty($imageInfo['bits']) ? $imageInfo['bits'] : 32;
 
 
 
 
 
 
2787
  }
2788
- // imgInfo[bits] is not always available
2789
- if (function_exists('memory_get_usage') && ini_get('memory_limit')) {
2790
- $MB = 1048576;
2791
- // number of bytes in 1M
2792
- $K64 = 65536;
2793
- // number of bytes in 64K
2794
- $TWEAKFACTOR = 1.68;
2795
- // Or whatever works for you
2796
- $memoryNeeded = round((doubleval($width * $height * $bits * $channels) / 8 + $K64) * $TWEAKFACTOR);
2797
- $memoryNeeded = memory_get_usage() + $memoryNeeded;
2798
- // get memory limit
2799
- $memory_limit = ini_get('memory_limit');
2800
- // PHP docs : Note that to have no memory limit, set this directive to -1.
2801
- if ($memory_limit == -1) {
2802
- return true;
2803
  }
2804
- // Just check megabyte limits, not higher
2805
- if (strtolower(substr($memory_limit, -1)) == 'm') {
2806
- if ($memory_limit != '') {
2807
- $memory_limit = intval(substr($memory_limit, 0, -1)) * 1024 * 1024;
 
 
 
 
 
 
 
 
 
 
 
 
 
2808
  }
2809
- if ($memoryNeeded > $memory_limit) {
2810
- $memoryNeeded = round($memoryNeeded / 1024 / 1024, 2);
2811
- $this->errmsg = 'Exceed Memory limit. Require : ' . $memoryNeeded . " MByte";
2812
- $this->error = true;
2813
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2814
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2815
  }
 
 
 
 
 
 
 
 
 
2816
  }
2817
- return true;
2818
- }
2819
- function __destruct()
2820
- {
2821
- $this->destruct();
2822
  }
2823
  /**
2824
- * Must be called to free up allocated memory after all manipulations are done
2825
- *
 
 
 
 
 
2826
  */
2827
- function destruct()
2828
  {
2829
- if (is_resource($this->newImage)) {
2830
- @ImageDestroy($this->newImage);
2831
- }
2832
- if (is_resource($this->oldImage)) {
2833
- @ImageDestroy($this->oldImage);
2834
- }
2835
- if (is_resource($this->workingImage)) {
2836
- @ImageDestroy($this->workingImage);
2837
  }
 
2838
  }
2839
  /**
2840
- * Returns the current width of the image
2841
- *
2842
- * @return int
2843
- */
2844
- function getCurrentWidth()
2845
- {
2846
- return $this->currentDimensions['width'];
2847
- }
2848
- /**
2849
- * Returns the current height of the image
2850
- *
2851
- * @return int
2852
- */
2853
- function getCurrentHeight()
2854
- {
2855
- return $this->currentDimensions['height'];
2856
- }
2857
- /**
2858
- * Calculates new image width
2859
- *
2860
- * @param int $width
2861
- * @param int $height
2862
- * @return array
2863
  */
2864
- function calcWidth($width, $height)
2865
  {
2866
- $newWp = 100 * $this->maxWidth / $width;
2867
- $newHeight = $height * $newWp / 100;
2868
- if (intval($newHeight) == $this->maxHeight - 1) {
2869
- $newHeight = $this->maxHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2870
  }
2871
- return array('newWidth' => intval($this->maxWidth), 'newHeight' => intval($newHeight));
2872
  }
2873
  /**
2874
- * Calculates new image height
2875
- *
2876
- * @param int $width
2877
- * @param int $height
2878
- * @return array
2879
  */
2880
- function calcHeight($width, $height)
2881
  {
2882
- $newHp = 100 * $this->maxHeight / $height;
2883
- $newWidth = $width * $newHp / 100;
2884
- if (intval($newWidth) == $this->maxWidth - 1) {
2885
- $newWidth = $this->maxWidth;
2886
  }
2887
- return array('newWidth' => intval($newWidth), 'newHeight' => intval($this->maxHeight));
2888
- }
2889
- /**
2890
- * Calculates new image size based on percentage
2891
- *
2892
- * @param int $width
2893
- * @param int $height
2894
- * @return array
2895
- */
2896
- function calcPercent($width, $height, $percent = -1)
2897
- {
2898
- if ($percent == -1) {
2899
- $percent = $this->percent;
2900
  }
2901
- $newWidth = $width * $percent / 100;
2902
- $newHeight = $height * $percent / 100;
2903
- return array('newWidth' => intval($newWidth), 'newHeight' => intval($newHeight));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2904
  }
2905
  /**
2906
- * Calculates new image size based on width and height, while constraining to maxWidth and maxHeight
2907
- *
2908
- * @param int $width
2909
- * @param int $height
2910
  */
2911
- function calcImageSize($width, $height)
2912
  {
2913
- // $width and $height are the CURRENT image resolutions
2914
- $ratio_w = $this->maxWidth / $width;
2915
- $ratio_h = $this->maxHeight / $height;
2916
- if ($ratio_w >= $ratio_h) {
2917
- $width = $this->maxWidth;
2918
- $height = (int) round($height * $ratio_h, 0);
 
 
 
 
 
 
 
2919
  } else {
2920
- $height = $this->maxHeight;
2921
- $width = (int) round($width * $ratio_w, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2922
  }
2923
- $this->newDimensions = array('newWidth' => $width, 'newHeight' => $height);
2924
  }
2925
- /**
2926
- * Calculates new image size based percentage
2927
- *
2928
- * @param int $width
2929
- * @param int $height
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2930
  */
2931
- function calcImageSizePercent($width, $height)
2932
  {
2933
- if ($this->percent > 0) {
2934
- $this->newDimensions = $this->calcPercent($width, $height);
2935
  }
 
2936
  }
2937
  /**
2938
- * Displays error image
2939
- *
 
2940
  */
2941
- function showErrorImage()
2942
  {
2943
- header('Content-type: image/png');
2944
- $errImg = ImageCreate(220, 25);
2945
- $bgColor = imagecolorallocate($errImg, 0, 0, 0);
2946
- $fgColor1 = imagecolorallocate($errImg, 255, 255, 255);
2947
- $fgColor2 = imagecolorallocate($errImg, 255, 0, 0);
2948
- imagestring($errImg, 3, 6, 6, 'Error:', $fgColor2);
2949
- imagestring($errImg, 3, 55, 6, $this->errmsg, $fgColor1);
2950
- imagepng($errImg);
2951
- imagedestroy($errImg);
2952
  }
2953
- /**
2954
- * Resizes image to fixed Width x Height
2955
- *
2956
- * @param int $Width
2957
- * @param int $Height
2958
- * @param int $deprecated Unused
2959
- */
2960
- function resizeFix($Width = 0, $Height = 0, $deprecated = 3)
2961
  {
2962
- if (!$this->checkMemoryForData($Width, $Height)) {
2963
- return;
 
2964
  }
2965
- $this->newWidth = $Width;
2966
- $this->newHeight = $Height;
2967
- if (function_exists("ImageCreateTrueColor")) {
2968
- $this->workingImage = ImageCreateTrueColor($this->newWidth, $this->newHeight);
2969
- } else {
2970
- $this->workingImage = ImageCreate($this->newWidth, $this->newHeight);
2971
  }
2972
- // ImageCopyResampled(
2973
- $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->currentDimensions['width'], $this->currentDimensions['height']);
2974
- $this->oldImage = $this->workingImage;
2975
- $this->newImage = $this->workingImage;
2976
- $this->currentDimensions['width'] = $this->newWidth;
2977
- $this->currentDimensions['height'] = $this->newHeight;
2978
  }
 
 
 
 
 
 
 
 
 
 
 
2979
  /**
2980
- * Resizes image to maxWidth x maxHeight
2981
- *
2982
- * @param int $maxWidth
2983
- * @param int $maxHeight
2984
- * @param int $deprecated Unused
2985
  */
2986
- function resize($maxWidth = 0, $maxHeight = 0, $deprecated = 3)
2987
  {
2988
- if (!$this->checkMemoryForData($maxWidth, $maxHeight)) {
2989
- return;
2990
- }
2991
- $this->maxWidth = $maxWidth;
2992
- $this->maxHeight = $maxHeight;
2993
- $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']);
2994
- if ($this->workingImage != null && $this->workingImage != $this->oldImage) {
2995
- ImageDestroy($this->workingImage);
2996
- $this->workingImage = null;
2997
- }
2998
- if (function_exists("ImageCreateTrueColor")) {
2999
- $this->workingImage = ImageCreateTrueColor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
3000
- } else {
3001
- $this->workingImage = ImageCreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
3002
  }
3003
- // ImageCopyResampled(
3004
- $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height']);
3005
- ImageDestroy($this->oldImage);
3006
- $this->oldImage = $this->workingImage;
3007
- $this->newImage = $this->workingImage;
3008
- $this->currentDimensions['width'] = $this->newDimensions['newWidth'];
3009
- $this->currentDimensions['height'] = $this->newDimensions['newHeight'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3010
  }
3011
  /**
3012
- * Resizes the image by $percent percent
3013
- *
3014
- * @param int $percent
3015
  */
3016
- function resizePercent($percent = 0)
3017
  {
3018
- $dims = $this->calcPercent($this->currentDimensions['width'], $this->currentDimensions['height'], $percent);
3019
- if (!$this->checkMemoryForData($dims['newWidth'], $dims['newHeight'])) {
3020
- return;
3021
- }
3022
- $this->percent = $percent;
3023
- $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']);
3024
- if (function_exists("ImageCreateTrueColor")) {
3025
- $this->workingImage = ImageCreateTrueColor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
3026
- } else {
3027
- $this->workingImage = ImageCreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
3028
  }
3029
- $this->ImageCopyResampled($this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height']);
3030
- $this->oldImage = $this->workingImage;
3031
- $this->newImage = $this->workingImage;
3032
- $this->currentDimensions['width'] = $this->newDimensions['newWidth'];
3033
- $this->currentDimensions['height'] = $this->newDimensions['newHeight'];
3034
  }
3035
  /**
3036
- * Crops the image from calculated center in a square of $cropSize pixels
 
 
3037
  *
3038
- * @param int $cropSize
3039
  */
3040
- function cropFromCenter($cropSize)
3041
  {
3042
- if ($cropSize > $this->currentDimensions['width']) {
3043
- $cropSize = $this->currentDimensions['width'];
3044
- }
3045
- if ($cropSize > $this->currentDimensions['height']) {
3046
- $cropSize = $this->currentDimensions['height'];
 
 
 
 
 
 
 
 
3047
  }
3048
- $cropX = intval(($this->currentDimensions['width'] - $cropSize) / 2);
3049
- $cropY = intval(($this->currentDimensions['height'] - $cropSize) / 2);
3050
- if ($this->workingImage != null && $this->workingImage != $this->oldImage) {
3051
- ImageDestroy($this->workingImage);
3052
- $this->workingImage = null;
3053
  }
3054
- if (function_exists("ImageCreateTrueColor")) {
3055
- $this->workingImage = ImageCreateTrueColor($cropSize, $cropSize);
 
 
 
 
 
 
3056
  } else {
3057
- $this->workingImage = ImageCreate($cropSize, $cropSize);
3058
  }
3059
- $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, $cropX, $cropY, $cropSize, $cropSize, $cropSize, $cropSize);
3060
- $this->oldImage = $this->workingImage;
3061
- $this->newImage = $this->workingImage;
3062
- $this->currentDimensions['width'] = $cropSize;
3063
- $this->currentDimensions['height'] = $cropSize;
 
3064
  }
3065
  /**
3066
- * Advanced cropping function that crops an image using $startX and $startY as the upper-left hand corner.
3067
- *
3068
- * @param int $startX
3069
- * @param int $startY
3070
- * @param int $width
3071
- * @param int $height
3072
  */
3073
- function crop($startX, $startY, $width, $height)
3074
  {
3075
- if (!$this->checkMemoryForData($width, $height)) {
3076
- return;
3077
- }
3078
- //make sure the cropped area is not greater than the size of the image
3079
- if ($width > $this->currentDimensions['width']) {
3080
- $width = $this->currentDimensions['width'];
3081
- }
3082
- if ($height > $this->currentDimensions['height']) {
3083
- $height = $this->currentDimensions['height'];
3084
- }
3085
- //make sure not starting outside the image
3086
- if ($startX + $width > $this->currentDimensions['width']) {
3087
- $startX = $this->currentDimensions['width'] - $width;
3088
- }
3089
- if ($startY + $height > $this->currentDimensions['height']) {
3090
- $startY = $this->currentDimensions['height'] - $height;
3091
- }
3092
- if ($startX < 0) {
3093
- $startX = 0;
3094
- }
3095
- if ($startY < 0) {
3096
- $startY = 0;
3097
  }
3098
- if ($this->workingImage != null && $this->workingImage != $this->oldImage) {
3099
- ImageDestroy($this->workingImage);
3100
- $this->workingImage = null;
 
 
3101
  }
3102
- if (function_exists("ImageCreateTrueColor")) {
3103
- $this->workingImage = ImageCreateTrueColor($width, $height);
3104
- } else {
3105
- $this->workingImage = ImageCreate($width, $height);
 
 
 
 
 
 
 
 
 
 
3106
  }
3107
- $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, $startX, $startY, $width, $height, $width, $height);
3108
- ImageDestroy($this->oldImage);
3109
- $this->oldImage = $this->workingImage;
3110
- $this->newImage = $this->workingImage;
3111
- $this->currentDimensions['width'] = $width;
3112
- $this->currentDimensions['height'] = $height;
3113
  }
3114
- /**
3115
- * Outputs the image to the screen, or saves to $name if supplied. Quality of JPEG images can be controlled with the $quality variable
3116
- *
3117
- * @param int $quality
3118
- * @param string $name
3119
- */
3120
- function show($quality = 100, $name = '')
3121
  {
3122
- switch ($this->format) {
3123
- case 'GIF':
3124
- if ($name != '') {
3125
- @ImageGif($this->newImage, $name) or $this->error = true;
3126
- } else {
3127
- header('Content-type: image/gif');
3128
- ImageGif($this->newImage);
3129
- }
3130
- break;
3131
- case 'JPG':
3132
- if ($name != '') {
3133
- @ImageJpeg($this->newImage, $name, $quality) or $this->error = true;
3134
- } else {
3135
- header('Content-type: image/jpeg');
3136
- ImageJpeg($this->newImage, NULL, $quality);
3137
- }
3138
- break;
3139
- case 'PNG':
3140
- if ($name != '') {
3141
- @ImagePng($this->newImage, $name) or $this->error = true;
3142
- } else {
3143
- header('Content-type: image/png');
3144
- ImagePng($this->newImage);
3145
- }
3146
- break;
3147
  }
 
3148
  }
3149
- /**
3150
- * Saves image as $name (can include file path), with quality of # percent if file is a jpeg
3151
- *
3152
- * @param string $name
3153
- * @param int $quality
3154
- * @return bool errorstate
3155
- */
3156
- function save($name, $quality = 100)
3157
  {
3158
- $this->show($quality, $name);
3159
- if ($this->error == true) {
3160
- $this->errmsg = 'Create Image failed. Check safe mode settings';
3161
- return false;
 
 
 
 
 
 
 
 
 
 
3162
  }
3163
- if (function_exists('do_action')) {
3164
- do_action('ngg_ajax_image_save', $name);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3165
  }
3166
- return true;
3167
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3168
  /**
3169
- * Creates Apple-style reflection under image, optionally adding a border to main image
3170
  *
3171
- * @param int $percent
3172
- * @param int $reflection
3173
- * @param int $white
3174
- * @param bool $border
3175
- * @param string $borderColor
3176
  */
3177
- function createReflection($percent, $reflection, $white, $border = true, $borderColor = '#a4a4a4')
3178
  {
3179
- $width = $this->currentDimensions['width'];
3180
- $height = $this->currentDimensions['height'];
3181
- $reflectionHeight = intval($height * ($reflection / 100));
3182
- $newHeight = $height + $reflectionHeight;
3183
- $reflectedPart = $height * ($percent / 100);
3184
- $this->workingImage = ImageCreateTrueColor($width, $newHeight);
3185
- ImageAlphaBlending($this->workingImage, true);
3186
- $colorToPaint = ImageColorAllocateAlpha($this->workingImage, 255, 255, 255, 0);
3187
- ImageFilledRectangle($this->workingImage, 0, 0, $width, $newHeight, $colorToPaint);
3188
- imagecopyresampled($this->workingImage, $this->newImage, 0, 0, 0, $reflectedPart, $width, $reflectionHeight, $width, $height - $reflectedPart);
3189
- $this->imageFlipVertical();
3190
- imagecopy($this->workingImage, $this->newImage, 0, 0, 0, 0, $width, $height);
3191
- imagealphablending($this->workingImage, true);
3192
- for ($i = 0; $i < $reflectionHeight; $i++) {
3193
- $colorToPaint = imagecolorallocatealpha($this->workingImage, 255, 255, 255, ($i / $reflectionHeight * -1 + 1) * $white);
3194
- imagefilledrectangle($this->workingImage, 0, $height + $i, $width, $height + $i, $colorToPaint);
3195
  }
3196
- if ($border == true) {
3197
- $rgb = $this->hex2rgb($borderColor, false);
3198
- $colorToPaint = imagecolorallocate($this->workingImage, $rgb[0], $rgb[1], $rgb[2]);
3199
- imageline($this->workingImage, 0, 0, $width, 0, $colorToPaint);
3200
- //top line
3201
- imageline($this->workingImage, 0, $height, $width, $height, $colorToPaint);
3202
- //bottom line
3203
- imageline($this->workingImage, 0, 0, 0, $height, $colorToPaint);
3204
- //left line
3205
- imageline($this->workingImage, $width - 1, 0, $width - 1, $height, $colorToPaint);
3206
- //right line
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3207
  }
3208
- $this->oldImage = $this->workingImage;
3209
- $this->newImage = $this->workingImage;
3210
- $this->currentDimensions['width'] = $width;
3211
- $this->currentDimensions['height'] = $newHeight;
 
 
 
3212
  }
3213
- /**
3214
- * Flip an image.
3215
- *
3216
- * @param bool $horz flip the image in horizontal mode
3217
- * @param bool $vert flip the image in vertical mode
3218
- * @return true
3219
- */
3220
- function flipImage($horz = false, $vert = false)
3221
  {
3222
- $sx = $vert ? $this->currentDimensions['width'] - 1 : 0;
3223
- $sy = $horz ? $this->currentDimensions['height'] - 1 : 0;
3224
- $sw = $vert ? -$this->currentDimensions['width'] : $this->currentDimensions['width'];
3225
- $sh = $horz ? -$this->currentDimensions['height'] : $this->currentDimensions['height'];
3226
- $this->workingImage = imagecreatetruecolor($this->currentDimensions['width'], $this->currentDimensions['height']);
3227
- $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, $sx, $sy, $this->currentDimensions['width'], $this->currentDimensions['height'], $sw, $sh);
3228
- $this->oldImage = $this->workingImage;
3229
- $this->newImage = $this->workingImage;
3230
- return true;
3231
  }
3232
- /**
3233
- * Rotate an image clockwise or counter clockwise
3234
- *
3235
- * @param string $dir Either CW or CCW
3236
- * @return bool
3237
- */
3238
- function rotateImage($dir = 'CW')
3239
  {
3240
- $angle = $dir == 'CW' ? 90 : -90;
3241
- return $this->rotateImageAngle($angle);
 
 
 
3242
  }
3243
  /**
3244
- * Rotate an image clockwise or counter clockwise
3245
  *
3246
- * @param int $angle Degrees to rotate the target image
3247
- * @return bool
3248
  */
3249
- function rotateImageAngle($angle = 90)
3250
  {
3251
- if (function_exists('imagerotate')) {
3252
- $this->currentDimensions['width'] = imagesx($this->workingImage);
3253
- $this->currentDimensions['height'] = imagesy($this->workingImage);
3254
- $this->oldImage = $this->workingImage;
3255
- // imagerotate() rotates CCW ;
3256
- // See for help: https://evertpot.com/115/
3257
- $this->newImage = imagerotate($this->oldImage, 360 - $angle, 0);
3258
- return true;
3259
  }
3260
- $this->workingImage = imagecreatetruecolor($this->currentDimensions['height'], $this->currentDimensions['width']);
3261
- imagealphablending($this->workingImage, false);
3262
- imagesavealpha($this->workingImage, true);
3263
- switch ($angle) {
3264
- case 90:
3265
- for ($x = 0; $x < $this->currentDimensions['width']; $x++) {
3266
- for ($y = 0; $y < $this->currentDimensions['height']; $y++) {
3267
- if (!imagecopy($this->workingImage, $this->oldImage, $this->currentDimensions['height'] - $y - 1, $x, $x, $y, 1, 1)) {
3268
- return false;
3269
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3270
  }
3271
  }
3272
- break;
3273
- case -90:
3274
- for ($x = 0; $x < $this->currentDimensions['width']; $x++) {
3275
- for ($y = 0; $y < $this->currentDimensions['height']; $y++) {
3276
- if (!imagecopy($this->workingImage, $this->oldImage, $y, $this->currentDimensions['width'] - $x - 1, $x, $y, 1, 1)) {
3277
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3278
  }
 
3279
  }
3280
  }
3281
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3282
  default:
3283
- return false;
3284
  }
3285
- $this->currentDimensions['width'] = imagesx($this->workingImage);
3286
- $this->currentDimensions['height'] = imagesy($this->workingImage);
3287
- $this->oldImage = $this->workingImage;
3288
- $this->newImage = $this->workingImage;
3289
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
3290
  }
3291
  /**
3292
- * Inverts working image, used by reflection function
3293
- *
3294
- * @access private
3295
  */
3296
- function imageFlipVertical()
3297
  {
3298
- $x_i = imagesx($this->workingImage);
3299
- $y_i = imagesy($this->workingImage);
3300
- for ($x = 0; $x < $x_i; $x++) {
3301
- for ($y = 0; $y < $y_i; $y++) {
3302
- imagecopy($this->workingImage, $this->workingImage, $x, $y_i - $y - 1, $x, $y, 1, 1);
3303
- }
3304
  }
 
3305
  }
3306
  /**
3307
- * Converts hexidecimal color value to rgb values and returns as array/string
3308
  *
3309
- * @param string $hex
3310
- * @param bool $asString
3311
- * @return array|string
3312
  */
3313
- function hex2rgb($hex, $asString = false)
3314
  {
3315
- // strip off any leading #
3316
- if (0 === strpos($hex, '#')) {
3317
- $hex = substr($hex, 1);
3318
- } else {
3319
- if (0 === strpos($hex, '&H')) {
3320
- $hex = substr($hex, 2);
3321
- }
3322
  }
3323
- // break into hex 3-tuple
3324
- $cutpoint = ceil(strlen($hex) / 2) - 1;
3325
- $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3);
3326
- // convert each tuple to decimal
3327
- $rgb[0] = isset($rgb[0]) ? hexdec($rgb[0]) : 0;
3328
- $rgb[1] = isset($rgb[1]) ? hexdec($rgb[1]) : 0;
3329
- $rgb[2] = isset($rgb[2]) ? hexdec($rgb[2]) : 0;
3330
- return $asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb;
3331
  }
3332
  /**
3333
- * Based on the Watermark function by Marek Malcherek
3334
- * http://www.malcherek.de
3335
  *
3336
- * @param string $color
3337
- * @param string $wmFont
3338
- * @param int $wmSize
3339
- * @param int $wmOpaque
3340
  */
3341
- function watermarkCreateText($color = '000000', $wmFont, $wmSize = 10, $wmOpaque = 90)
3342
  {
3343
- // set font path
3344
- $wmFontPath = NGGALLERY_ABSPATH . "fonts/" . $wmFont;
3345
- if (!is_readable($wmFontPath)) {
3346
- return;
3347
- }
3348
- // This function requires both the GD library and the FreeType library.
3349
- if (!function_exists('ImageTTFBBox')) {
3350
- return;
3351
- }
3352
- $words = preg_split('/ /', $this->watermarkText);
3353
- $lines = array();
3354
- $line = '';
3355
- $watermark_image_width = 0;
3356
- // attempt adding a new word until the width is too large; then start a new line and start again
3357
- foreach ($words as $word) {
3358
- // sanitize the text being input; imagettftext() can be sensitive
3359
- $TextSize = $this->ImageTTFBBoxDimensions($wmSize, 0, $this->correct_gd_unc_path($wmFontPath), $line . preg_replace('~^(&([a-zA-Z0-9]);)~', htmlentities('${1}'), mb_convert_encoding($word, "HTML-ENTITIES", "UTF-8")));
3360
- if ($watermark_image_width == 0) {
3361
- $watermark_image_width = $TextSize['width'];
3362
- }
3363
- if ($TextSize['width'] > $this->newDimensions['newWidth']) {
3364
- $lines[] = trim($line);
3365
- $line = '';
3366
- } else {
3367
- if ($TextSize['width'] > $watermark_image_width) {
3368
- $watermark_image_width = $TextSize['width'];
3369
- }
3370
- }
3371
- $line .= $word . ' ';
3372
- }
3373
- $lines[] = trim($line);
3374
- // use this string to determine our largest possible line height
3375
- $line_dimensions = $this->ImageTTFBBoxDimensions($wmSize, 0, $this->correct_gd_unc_path($wmFontPath), 'MXQJALYmxqjabdfghjklpqry019`@$^&*(,!132');
3376
- $line_height = $line_dimensions['height'] * 1.05;
3377
- // Create an image to apply our text to
3378
- $this->workingImage = ImageCreateTrueColor($watermark_image_width, count($lines) * $line_height);
3379
- ImageSaveAlpha($this->workingImage, true);
3380
- ImageAlphaBlending($this->workingImage, false);
3381
- $bgText = imagecolorallocatealpha($this->workingImage, 255, 255, 255, 127);
3382
- imagefill($this->workingImage, 0, 0, $bgText);
3383
- $wmTransp = 127 - $wmOpaque * 1.27;
3384
- $rgb = $this->hex2rgb($color, false);
3385
- $TextColor = imagecolorallocatealpha($this->workingImage, $rgb[0], $rgb[1], $rgb[2], $wmTransp);
3386
- // Put text on the image, line-by-line
3387
- $y_pos = $wmSize;
3388
- foreach ($lines as $line) {
3389
- imagettftext($this->workingImage, $wmSize, 0, 0, $y_pos, $TextColor, $this->correct_gd_unc_path($wmFontPath), $line);
3390
- $y_pos += $line_height;
3391
- }
3392
- $this->watermarkImgPath = $this->workingImage;
3393
- return;
3394
  }
3395
  /**
3396
- * Returns a path that can be used with imagettftext() and ImageTTFBBox()
3397
  *
3398
- * imagettftext() and ImageTTFBBox() cannot load resources from Windows UNC paths
3399
- * and require they be mangled to be like //server\filename instead of \\server\filename
3400
- * @param string $path Absolute file path
3401
- * @return string $path Mangled absolute file path
3402
  */
3403
- public function correct_gd_unc_path($path)
3404
  {
3405
- if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && substr($path, 0, 2) === '\\\\') {
3406
- $path = ltrim($path, '\\\\');
3407
- $path = '//' . $path;
 
 
 
 
 
 
 
 
 
 
3408
  }
3409
- return $path;
 
 
 
 
 
 
 
 
3410
  }
3411
  /**
3412
- * Calculates the width & height dimensions of ImageTTFBBox().
3413
  *
3414
- * Note: ImageTTFBBox() is unreliable with large font sizes
3415
- * @param $wmSize
3416
- * @param $fontAngle
3417
- * @param $wmFontPath
3418
- * @param $text
3419
- * @return array
3420
  */
3421
- function ImageTTFBBoxDimensions($wmSize, $fontAngle, $wmFontPath, $text)
3422
  {
3423
- $box = @ImageTTFBBox($wmSize, $fontAngle, $this->correct_gd_unc_path($wmFontPath), $text);
3424
- $max_x = max(array($box[0], $box[2], $box[4], $box[6]));
3425
- $max_y = max(array($box[1], $box[3], $box[5], $box[7]));
3426
- $min_x = min(array($box[0], $box[2], $box[4], $box[6]));
3427
- $min_y = min(array($box[1], $box[3], $box[5], $box[7]));
3428
- return array("width" => $max_x - $min_x, "height" => $max_y - $min_y);
3429
  }
3430
- function applyFilter($filterType)
 
 
 
 
 
3431
  {
3432
- $args = func_get_args();
3433
- array_unshift($args, $this->newImage);
3434
- return call_user_func_array('imagefilter', $args);
3435
  }
3436
  /**
3437
- * Modfied Watermark function by Steve Peart
3438
- * http://parasitehosting.com/
3439
  *
3440
- * @param string $relPOS
3441
- * @param int $xPOS
3442
- * @param int $yPOS
 
3443
  */
3444
- function watermarkImage($relPOS = 'botRight', $xPOS = 0, $yPOS = 0)
3445
  {
3446
- // if it's a resource ID take it as watermark text image
3447
- if (is_resource($this->watermarkImgPath)) {
3448
- $this->workingImage = $this->watermarkImgPath;
3449
- } else {
3450
- // (possibly) search for the file from the document root
3451
- if (!is_file($this->watermarkImgPath)) {
3452
- $fs = C_Fs::get_instance();
3453
- if (is_file($fs->join_paths($fs->get_document_root('content'), $this->watermarkImgPath))) {
3454
- $this->watermarkImgPath = $fs->get_document_root('content') . $this->watermarkImgPath;
3455
- }
3456
- }
3457
- // Would you really want to use anything other than a png?
3458
- $this->workingImage = @imagecreatefrompng($this->watermarkImgPath);
3459
- // if it's not a valid file die...
3460
- if (empty($this->workingImage) or !$this->workingImage) {
3461
- return;
3462
- }
3463
- }
3464
- imagealphablending($this->workingImage, false);
3465
- imagesavealpha($this->workingImage, true);
3466
- $sourcefile_width = imageSX($this->oldImage);
3467
- $sourcefile_height = imageSY($this->oldImage);
3468
- $watermarkfile_width = imageSX($this->workingImage);
3469
- $watermarkfile_height = imageSY($this->workingImage);
3470
- switch (substr($relPOS, 0, 3)) {
3471
- case 'top':
3472
- $dest_y = 0 + $yPOS;
3473
- break;
3474
- case 'mid':
3475
- $dest_y = $sourcefile_height / 2 - $watermarkfile_height / 2;
3476
- break;
3477
- case 'bot':
3478
- $dest_y = $sourcefile_height - $watermarkfile_height - $yPOS;
3479
- break;
3480
- default:
3481
- $dest_y = 0;
3482
- break;
3483
- }
3484
- switch (substr($relPOS, 3)) {
3485
- case 'Left':
3486
- $dest_x = 0 + $xPOS;
3487
- break;
3488
- case 'Center':
3489
- $dest_x = $sourcefile_width / 2 - $watermarkfile_width / 2;
3490
- break;
3491
- case 'Right':
3492
- $dest_x = $sourcefile_width - $watermarkfile_width - $xPOS;
3493
- break;
3494
- default:
3495
- $dest_x = 0;
3496
- break;
3497
- }
3498
- // debug
3499
- // $this->errmsg = 'X '.$dest_x.' Y '.$dest_y;
3500
- // $this->showErrorImage();
3501
- // if a gif, we have to upsample it to a truecolor image
3502
- if ($this->format == 'GIF') {
3503
- $tempimage = imagecreatetruecolor($sourcefile_width, $sourcefile_height);
3504
- imagecopy($tempimage, $this->oldImage, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height);
3505
- $this->newImage = $tempimage;
3506
  }
3507
- $this->imagecopymerge_alpha($this->newImage, $this->workingImage, $dest_x, $dest_y, 0, 0, $watermarkfile_width, $watermarkfile_height, 100);
 
 
 
 
 
 
 
 
3508
  }
3509
  /**
3510
- * Wrapper to imagecopymerge() that allows PNG transparency
3511
  */
3512
- function imagecopymerge_alpha($destination_image, $source_image, $destination_x, $destination_y, $source_x, $source_y, $source_w, $source_h, $pct)
3513
  {
3514
- $cut = imagecreatetruecolor($source_w, $source_h);
3515
- imagecopy($cut, $destination_image, 0, 0, $destination_x, $destination_y, $source_w, $source_h);
3516
- imagecopy($cut, $source_image, 0, 0, $source_x, $source_y, $source_w, $source_h);
3517
- imagecopymerge($destination_image, $cut, $destination_x, $destination_y, 0, 0, $source_w, $source_h, $pct);
3518
  }
3519
  /**
3520
- * Modfied imagecopyresampled function to save transparent images
3521
- * See : http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/
3522
- * @since 1.9.0
3523
- *
3524
- * @param resource $dst_image
3525
- * @param resource $src_image
3526
- * @param int $dst_x
3527
- * @param int $dst_y
3528
- * @param int $src_x
3529
- * @param int $src_y
3530
- * @param int $dst_w
3531
- * @param int $dst_h
3532
- * @param int $src_w
3533
- * @param int $src_h
3534
- * @return bool
3535
  */
3536
- function imagecopyresampled(&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
3537
  {
3538
- // Check if this image is PNG or GIF, then set if Transparent
3539
- if ($this->format == 'GIF' || $this->format == 'PNG') {
3540
- imagealphablending($dst_image, false);
3541
- imagesavealpha($dst_image, true);
3542
- $transparent = imagecolorallocatealpha($dst_image, 255, 255, 255, 127);
3543
- imagefilledrectangle($dst_image, 0, 0, $dst_w, $dst_h, $transparent);
3544
- }
3545
- imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
3546
- return true;
3547
  }
3548
- }
3549
- /**
3550
- * Basic gallery storage methods; please consult the other available mixin.gallerystorage_base_(.*).php files before
3551
- * adding new methods to this class: new methods may be more appropriately defined in other mixins.
3552
- * @property C_Gallery_Storage $object
3553
- */
3554
- class Mixin_GalleryStorage_Base extends Mixin
3555
- {
3556
  /**
3557
- * Gets the id of a gallery, regardless of whether an integer
3558
- * or object was passed as an argument
3559
- * @param mixed $gallery_obj_or_id
3560
- * @return null|int
3561
  */
3562
- function _get_gallery_id($gallery_obj_or_id)
3563
  {
3564
- $retval = NULL;
3565
- $gallery_key = $this->object->_gallery_mapper->get_primary_key_column();
3566
- if (is_object($gallery_obj_or_id)) {
3567
- if (isset($gallery_obj_or_id->{$gallery_key})) {
3568
- $retval = $gallery_obj_or_id->{$gallery_key};
3569
- }
3570
- } elseif (is_numeric($gallery_obj_or_id)) {
3571
- $retval = $gallery_obj_or_id;
3572
- }
3573
- return $retval;
3574
  }
3575
- /**
3576
- * Outputs/renders an image
3577
- * @param int|stdClass|C_Image $image
3578
- * @return bool
3579
- */
3580
- function render_image($image, $size = FALSE)
3581
  {
3582
- $format_list = $this->object->get_image_format_list();
3583
- $abspath = $this->object->get_image_abspath($image, $size, true);
3584
- if ($abspath == null) {
3585
- $thumbnail = $this->object->generate_image_size($image, $size);
3586
- if ($thumbnail != null) {
3587
- $abspath = $thumbnail->fileName;
3588
- $thumbnail->destruct();
3589
- }
 
 
3590
  }
3591
- if ($abspath != null) {
3592
- $data = @getimagesize($abspath);
3593
- $format = 'jpg';
3594
- if ($data != null && is_array($data) && isset($format_list[$data[2]])) {
3595
- $format = $format_list[$data[2]];
3596
- }
3597
- // Clear output
3598
- while (ob_get_level() > 0) {
3599
- ob_end_clean();
3600
- }
3601
- $format = strtolower($format);
3602
- // output image and headers
3603
- header('Content-type: image/' . $format);
3604
- readfile($abspath);
3605
- return true;
3606
  }
3607
- return false;
 
 
 
3608
  }
3609
  /**
3610
- * Sets a NGG image as a post thumbnail for the given post
3611
  *
3612
- * @param int $postId
3613
- * @param int|C_Image|stdClass $image
3614
- * @param bool $only_create_attachment
3615
- * @return int
3616
  */
3617
- function set_post_thumbnail($postId, $image, $only_create_attachment = FALSE)
3618
  {
3619
- $retval = FALSE;
3620
- // Get the post ID
3621
- if (is_object($postId)) {
3622
- $post = $postId;
3623
- $postId = isset($post->ID) ? $post->ID : $post->post_id;
3624
- }
3625
- // Get the image
3626
- if (is_int($image)) {
3627
- $imageId = $image;
3628
- $mapper = C_Image_Mapper::get_instance();
3629
- $image = $mapper->find($imageId);
3630
- }
3631
- if ($image && $postId) {
3632
- $attachment_id = $this->object->is_in_media_library($image->pid);
3633
- if ($attachment_id === FALSE) {
3634
- $attachment_id = $this->object->copy_to_media_library($image);
3635
- }
3636
- if ($attachment_id) {
3637
- if (!$only_create_attachment) {
3638
- set_post_thumbnail($postId, $attachment_id);
3639
- }
3640
- $retval = $attachment_id;
3641
- }
3642
  }
3643
- return $retval;
3644
  }
3645
- function convert_slashes($path)
 
 
 
3646
  {
3647
- $search = array('/', "\\");
3648
- $replace = array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR);
3649
- return str_replace($search, $replace, $path);
3650
  }
3651
- /**
3652
- * Empties the gallery cache directory of content
3653
- * @param object $gallery
3654
- */
3655
- function flush_cache($gallery)
3656
  {
3657
- $cache = C_Cache::get_instance();
3658
- $cache->flush_directory($this->object->get_cache_abspath($gallery));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3659
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3660
  /**
3661
- * Sanitizes a directory path, replacing whitespace with dashes.
3662
- *
3663
- * Taken from WP' sanitize_file_name() and modified to not act on file extensions.
3664
- *
3665
- * Removes special characters that are illegal in filenames on certain
3666
- * operating systems and special characters requiring special escaping
3667
- * to manipulate at the command line. Replaces spaces and consecutive
3668
- * dashes with a single dash. Trims period, dash and underscore from beginning
3669
- * and end of filename. It is not guaranteed that this function will return a
3670
- * filename that is allowed to be uploaded.
3671
- * @param string $dirname The directory name to be sanitized
3672
- * @return string The sanitized directory name
3673
  */
3674
- public function sanitize_directory_name($dirname)
3675
  {
3676
- $dirname_raw = $dirname;
3677
- $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "\$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0));
3678
- $special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $dirname_raw);
3679
- $dirname = preg_replace("#\\x{00a0}#siu", ' ', $dirname);
3680
- $dirname = str_replace($special_chars, '', $dirname);
3681
- $dirname = str_replace(array('%20', '+'), '-', $dirname);
3682
- $dirname = preg_replace('/[\\r\\n\\t -]+/', '-', $dirname);
3683
- $dirname = trim($dirname, '.-_');
3684
- return $dirname;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3685
  }
3686
- }
3687
- /**
3688
- * Provides methods to C_Gallery_Storage related to dynamic images, thumbnails, clones, etc
3689
- * @property C_Gallery_Storage $object
3690
- */
3691
- class Mixin_GalleryStorage_Base_Dynamic extends Mixin
3692
- {
3693
  /**
3694
- * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated
3695
- * @param object|int $image Image ID or an image object
3696
- * @param string $size
3697
- * @param array $params
3698
- * @param bool $skip_defaults
3699
- * @return bool|array
3700
  */
3701
- function calculate_image_size_dimensions($image, $size, $params = null, $skip_defaults = false)
3702
  {
3703
- $retval = FALSE;
3704
- // Get the image entity
3705
- if (is_numeric($image)) {
3706
- $image = $this->object->_image_mapper->find($image);
3707
  }
3708
- // Ensure we have a valid image
3709
- if ($image) {
3710
- $params = $this->object->get_image_size_params($image, $size, $params, $skip_defaults);
3711
- // Get the image filename
3712
- $image_path = $this->object->get_original_abspath($image, 'original');
3713
- $clone_path = $this->object->get_image_abspath($image, $size);
3714
- $retval = $this->object->calculate_image_clone_dimensions($image_path, $clone_path, $params);
3715
  }
3716
- return $retval;
 
 
 
 
 
 
 
 
 
 
 
 
3717
  }
3718
  /**
3719
- * Generates a "clone" for an existing image, the clone can be altered using the $params array
3720
- * @param string $image_path
3721
- * @param string $clone_path
3722
- * @param array $params
3723
- * @return null|object
3724
  */
3725
- function generate_image_clone($image_path, $clone_path, $params)
3726
  {
3727
- $crop = isset($params['crop']) ? $params['crop'] : NULL;
3728
- $watermark = isset($params['watermark']) ? $params['watermark'] : NULL;
3729
- $reflection = isset($params['reflection']) ? $params['reflection'] : NULL;
3730
- $rotation = isset($params['rotation']) ? $params['rotation'] : NULL;
3731
- $flip = isset($params['flip']) ? $params['flip'] : NULL;
3732
- $destpath = NULL;
3733
- $thumbnail = NULL;
3734
- $result = $this->object->calculate_image_clone_result($image_path, $clone_path, $params);
3735
- // XXX this should maybe be removed and extra settings go into $params?
3736
- $settings = apply_filters('ngg_settings_during_image_generation', C_NextGen_Settings::get_instance()->to_array());
3737
- // Ensure we have a valid image
3738
- if ($image_path && @file_exists($image_path) && $result != null && !isset($result['error'])) {
3739
- $image_dir = dirname($image_path);
3740
- $clone_path = $result['clone_path'];
3741
- $clone_dir = $result['clone_directory'];
3742
- $clone_format = $result['clone_format'];
3743
- $format_list = $this->object->get_image_format_list();
3744
- // Ensure target directory exists, but only create 1 subdirectory
3745
- if (!@file_exists($clone_dir)) {
3746
- if (strtolower(realpath($image_dir)) != strtolower(realpath($clone_dir))) {
3747
- if (strtolower(realpath($image_dir)) == strtolower(realpath(dirname($clone_dir)))) {
3748
- wp_mkdir_p($clone_dir);
3749
- }
3750
  }
3751
- }
3752
- $method = $result['method'];
3753
- $width = $result['width'];
3754
- $height = $result['height'];
3755
- $quality = $result['quality'];
3756
- if ($quality == null) {
3757
- $quality = 100;
3758
- }
3759
- if ($method == 'wordpress') {
3760
- $original = wp_get_image_editor($image_path);
3761
- $destpath = $clone_path;
3762
- if (!is_wp_error($original)) {
3763
- $original->resize($width, $height, $crop);
3764
- $original->set_quality($quality);
3765
- $original->save($clone_path);
3766
  }
3767
- } else {
3768
- if ($method == 'nextgen') {
3769
- $destpath = $clone_path;
3770
- $thumbnail = new C_NggLegacy_Thumbnail($image_path, true);
3771
- if (!$thumbnail->error) {
3772
- if ($crop) {
3773
- $crop_area = $result['crop_area'];
3774
- $crop_x = $crop_area['x'];
3775
- $crop_y = $crop_area['y'];
3776
- $crop_width = $crop_area['width'];
3777
- $crop_height = $crop_area['height'];
3778
- $thumbnail->crop($crop_x, $crop_y, $crop_width, $crop_height);
3779
- }
3780
- $thumbnail->resize($width, $height);
3781
  } else {
3782
- $thumbnail = NULL;
 
 
3783
  }
3784
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3785
  }
3786
- // We successfully generated the thumbnail
3787
- if (is_string($destpath) && (@file_exists($destpath) || $thumbnail != null)) {
3788
- if ($clone_format != null) {
3789
- if (isset($format_list[$clone_format])) {
3790
- $clone_format_extension = $format_list[$clone_format];
3791
- $clone_format_extension_str = null;
3792
- if ($clone_format_extension != null) {
3793
- $clone_format_extension_str = '.' . $clone_format_extension;
3794
- }
3795
- $destpath_info = M_I18n::mb_pathinfo($destpath);
3796
- $destpath_extension = $destpath_info['extension'];
3797
- if (strtolower($destpath_extension) != strtolower($clone_format_extension)) {
3798
- $destpath_dir = $destpath_info['dirname'];
3799
- $destpath_basename = $destpath_info['filename'];
3800
- $destpath_new = $destpath_dir . DIRECTORY_SEPARATOR . $destpath_basename . $clone_format_extension_str;
3801
- if (@file_exists($destpath) && rename($destpath, $destpath_new) || $thumbnail != null) {
3802
- $destpath = $destpath_new;
3803
- }
3804
- }
3805
- }
3806
  }
3807
- if (is_null($thumbnail)) {
3808
- $thumbnail = new C_NggLegacy_Thumbnail($destpath, true);
3809
- if ($thumbnail->error) {
3810
- $thumbnail = null;
3811
- return null;
3812
- }
3813
- } else {
3814
- $thumbnail->fileName = $destpath;
3815
  }
3816
- // This is quite odd, when watermark equals int(0) it seems all statements below ($watermark == 'image') and ($watermark == 'text') both evaluate as true
3817
- // so we set it at null if it evaluates to any null-like value
3818
- if ($watermark == null) {
3819
- $watermark = null;
3820
  }
3821
- if ($watermark == 1 || $watermark === true) {
3822
- $watermark_setting_keys = array('wmFont', 'wmType', 'wmPos', 'wmXpos', 'wmYpos', 'wmPath', 'wmText', 'wmOpaque', 'wmFont', 'wmSize', 'wmColor');
3823
- foreach ($watermark_setting_keys as $watermark_key) {
3824
- if (!isset($params[$watermark_key])) {
3825
- $params[$watermark_key] = $settings[$watermark_key];
3826
- }
3827
- }
3828
- if (in_array(strval($params['wmType']), array('image', 'text'))) {
3829
- $watermark = $params['wmType'];
3830
- } else {
3831
- $watermark = 'text';
3832
- }
3833
  }
3834
- $watermark = strval($watermark);
3835
- if ($watermark == 'image') {
3836
- $thumbnail->watermarkImgPath = $params['wmPath'];
3837
- $thumbnail->watermarkImage($params['wmPos'], $params['wmXpos'], $params['wmYpos']);
3838
- } else {
3839
- if ($watermark == 'text') {
3840
- $thumbnail->watermarkText = $params['wmText'];
3841
- $thumbnail->watermarkCreateText($params['wmColor'], $params['wmFont'], $params['wmSize'], $params['wmOpaque']);
3842
- $thumbnail->watermarkImage($params['wmPos'], $params['wmXpos'], $params['wmYpos']);
3843
- }
3844
  }
3845
- if ($rotation && in_array(abs($rotation), array(90, 180, 270))) {
3846
- $thumbnail->rotateImageAngle($rotation);
3847
- $remove_orientation_exif = TRUE;
3848
- } else {
3849
- $remove_orientation_exif = FALSE;
3850
  }
3851
- $flip = strtolower($flip);
3852
- if ($flip && in_array($flip, array('h', 'v', 'hv'))) {
3853
- $flip_h = in_array($flip, array('h', 'hv'));
3854
- $flip_v = in_array($flip, array('v', 'hv'));
3855
- $thumbnail->flipImage($flip_h, $flip_v);
3856
  }
3857
- if ($reflection) {
3858
- $thumbnail->createReflection(40, 40, 50, FALSE, '#a4a4a4');
3859
  }
3860
- if ($clone_format != null && isset($format_list[$clone_format])) {
3861
- // Force format
3862
- $thumbnail->format = strtoupper($format_list[$clone_format]);
3863
  }
3864
- $thumbnail = apply_filters('ngg_before_save_thumbnail', $thumbnail);
3865
- // Always retrieve metadata from the backup when possible
3866
- $backup_path = $image_path . '_backup';
3867
- $exif_abspath = @file_exists($backup_path) ? $backup_path : $image_path;
3868
- $exif_iptc = @C_Exif_Writer::read_metadata($exif_abspath);
3869
- $thumbnail->save($destpath, $quality);
3870
- @C_Exif_Writer::write_metadata($destpath, $exif_iptc);
3871
  }
 
3872
  }
3873
- return $thumbnail;
 
 
 
 
 
 
 
 
 
3874
  }
3875
- /**
3876
- * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated
3877
- * @param string $image_path
3878
- * @param string $clone_path
3879
- * @param array $params
3880
- * @return null|array
3881
- */
3882
- function calculate_image_clone_dimensions($image_path, $clone_path, $params)
3883
  {
3884
- $retval = null;
3885
- $result = $this->object->calculate_image_clone_result($image_path, $clone_path, $params);
3886
- if ($result != null) {
3887
- $retval = array('width' => $result['width'], 'height' => $result['height'], 'real_width' => $result['real_width'], 'real_height' => $result['real_height']);
 
 
 
 
 
 
 
 
 
 
3888
  }
3889
  return $retval;
3890
  }
3891
  /**
3892
- * Returns an array of properties of a resulting clone image if and when generated
3893
- * @param string $image_path
3894
- * @param string $clone_path
3895
- * @param array $params
3896
- * @return null|array
3897
  */
3898
- function calculate_image_clone_result($image_path, $clone_path, $params)
3899
  {
3900
- $width = isset($params['width']) ? $params['width'] : NULL;
3901
- $height = isset($params['height']) ? $params['height'] : NULL;
3902
- $quality = isset($params['quality']) ? $params['quality'] : NULL;
3903
- $type = isset($params['type']) ? $params['type'] : NULL;
3904
- $crop = isset($params['crop']) ? $params['crop'] : NULL;
3905
- $watermark = isset($params['watermark']) ? $params['watermark'] : NULL;
3906
- $rotation = isset($params['rotation']) ? $params['rotation'] : NULL;
3907
- $reflection = isset($params['reflection']) ? $params['reflection'] : NULL;
3908
- $crop_frame = isset($params['crop_frame']) ? $params['crop_frame'] : NULL;
3909
- $result = NULL;
3910
- // Ensure we have a valid image
3911
- if ($image_path && @file_exists($image_path)) {
3912
- // Ensure target directory exists, but only create 1 subdirectory
3913
- $image_dir = dirname($image_path);
3914
- $clone_dir = dirname($clone_path);
3915
- $image_extension = M_I18n::mb_pathinfo($image_path, PATHINFO_EXTENSION);
3916
- $image_extension_str = null;
3917
- $clone_extension = M_I18n::mb_pathinfo($clone_path, PATHINFO_EXTENSION);
3918
- $clone_extension_str = null;
3919
- if ($image_extension != null) {
3920
- $image_extension_str = '.' . $image_extension;
3921
- }
3922
- if ($clone_extension != null) {
3923
- $clone_extension_str = '.' . $clone_extension;
3924
- }
3925
- $image_basename = M_I18n::mb_basename($image_path);
3926
- $clone_basename = M_I18n::mb_basename($clone_path);
3927
- // We use a default suffix as passing in null as the suffix will make WordPress use a default
3928
- $clone_suffix = null;
3929
- $format_list = $this->object->get_image_format_list();
3930
- $clone_format = null;
3931
- // format is determined below and based on $type otherwise left to null
3932
- // suffix is only used to reconstruct paths for image_resize function
3933
- if (strpos($clone_basename, $image_basename) === 0) {
3934
- $clone_suffix = substr($clone_basename, strlen($image_basename));
3935
- }
3936
- if ($clone_suffix != null && $clone_suffix[0] == '-') {
3937
- // WordPress adds '-' on its own
3938
- $clone_suffix = substr($clone_suffix, 1);
3939
- }
3940
- // Get original image dimensions
3941
- $dimensions = getimagesize($image_path);
3942
- if ($width == null && $height == null) {
3943
- if ($dimensions != null) {
3944
- if ($width == null) {
3945
- $width = $dimensions[0];
3946
- }
3947
- if ($height == null) {
3948
- $height = $dimensions[1];
3949
- }
3950
- } else {
3951
- // XXX Don't think there's any other option here but to fail miserably...use some hard-coded defaults maybe?
3952
- return null;
3953
- }
3954
- }
3955
- if ($dimensions != null) {
3956
- $dimensions_ratio = $dimensions[0] / $dimensions[1];
3957
- if ($width == null) {
3958
- $width = (int) round($height * $dimensions_ratio);
3959
- if ($width == $dimensions[0] - 1) {
3960
- $width = $dimensions[0];
3961
- }
3962
- } else {
3963
- if ($height == null) {
3964
- $height = (int) round($width / $dimensions_ratio);
3965
- if ($height == $dimensions[1] - 1) {
3966
- $height = $dimensions[1];
3967
- }
3968
- }
3969
- }
3970
- if ($width > $dimensions[0]) {
3971
- $width = $dimensions[0];
3972
- }
3973
- if ($height > $dimensions[1]) {
3974
- $height = $dimensions[1];
3975
- }
3976
- $image_format = $dimensions[2];
3977
- if ($type != null) {
3978
- if (is_string($type)) {
3979
- $type = strtolower($type);
3980
- // Indexes in the $format_list array correspond to IMAGETYPE_XXX values appropriately
3981
- if (($index = array_search($type, $format_list)) !== false) {
3982
- $type = $index;
3983
- if ($type != $image_format) {
3984
- // Note: this only changes the FORMAT of the image but not the extension
3985
- $clone_format = $type;
3986
- }
3987
- }
3988
- }
3989
  }
3990
  }
3991
- if ($width == null || $height == null) {
3992
- // Something went wrong...
3993
- return null;
3994
- }
3995
- // We now need to estimate the 'quality' or level of compression applied to the original JPEG: *IF* the
3996
- // original image has a quality lower than the $quality parameter we will end up generating a new image
3997
- // that is MUCH larger than the original. 'Quality' as an EXIF or IPTC property is quite unreliable
3998
- // and not all software honors or treats it the same way. This calculation is simple: just compare the size
3999
- // that our image could become to what it currently is. '3' is important here as JPEG uses 3 bytes per pixel.
4000
- //
4001
- // First we attempt to use ImageMagick if we can; it has a more robust method of calculation.
4002
- if (!empty($dimensions['mime']) && $dimensions['mime'] == 'image/jpeg') {
4003
- $possible_quality = NULL;
4004
- $try_image_magick = TRUE;
4005
- if (function_exists('is_wpe') && ($dimensions[0] >= 8000 || $dimensions[1] >= 8000)) {
4006
- $try_image_magick = FALSE;
4007
- }
4008
- if ($try_image_magick && extension_loaded('imagick') && class_exists('Imagick')) {
4009
- $img = new Imagick($image_path);
4010
- if (method_exists($img, 'getImageCompressionQuality')) {
4011
- $possible_quality = $img->getImageCompressionQuality();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4012
  }
4013
- }
4014
- // ImageMagick wasn't available so we guess it from the dimensions and filesize
4015
- if ($possible_quality === NULL) {
4016
- $filesize = filesize($image_path);
4017
- $possible_quality = 101 - $width * $height * 3 / $filesize;
4018
- }
4019
- if ($possible_quality !== NULL && $possible_quality < $quality) {
4020
- $quality = $possible_quality;
4021
- }
4022
- }
4023
- $result['clone_path'] = $clone_path;
4024
- $result['clone_directory'] = $clone_dir;
4025
- $result['clone_suffix'] = $clone_suffix;
4026
- $result['clone_format'] = $clone_format;
4027
- $result['base_width'] = $dimensions[0];
4028
- $result['base_height'] = $dimensions[1];
4029
- // image_resize() has limitations:
4030
- // - no easy crop frame support
4031
- // - fails if the dimensions are unchanged
4032
- // - doesn't support filename prefix, only suffix so names like thumbs_original_name.jpg for $clone_path are not supported
4033
- // also suffix cannot be null as that will make WordPress use a default suffix...we could use an object that returns empty string from __toString() but for now just fallback to ngg generator
4034
- if (FALSE) {
4035
- // disabling the WordPress method for Iteration #6
4036
- // if (($crop_frame == null || !$crop) && ($dimensions[0] != $width && $dimensions[1] != $height) && $clone_suffix != null)
4037
- $result['method'] = 'wordpress';
4038
- $new_dims = image_resize_dimensions($dimensions[0], $dimensions[1], $width, $height, $crop);
4039
- if ($new_dims) {
4040
- list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $new_dims;
4041
- $width = $dst_w;
4042
- $height = $dst_h;
4043
- } else {
4044
- $result['error'] = new WP_Error('error_getting_dimensions', __('Could not calculate resized image dimensions'));
4045
- }
4046
- } else {
4047
- $result['method'] = 'nextgen';
4048
- $original_width = $dimensions[0];
4049
- $original_height = $dimensions[1];
4050
- $aspect_ratio = $width / $height;
4051
- $orig_ratio_x = $original_width / $width;
4052
- $orig_ratio_y = $original_height / $height;
4053
- if ($crop) {
4054
- $algo = 'shrink';
4055
- // either 'adapt' or 'shrink'
4056
- if ($crop_frame != null) {
4057
- $crop_x = (int) round($crop_frame['x']);
4058
- $crop_y = (int) round($crop_frame['y']);
4059
- $crop_width = (int) round($crop_frame['width']);
4060
- $crop_height = (int) round($crop_frame['height']);
4061
- $crop_final_width = (int) round($crop_frame['final_width']);
4062
- $crop_final_height = (int) round($crop_frame['final_height']);
4063
- $crop_width_orig = $crop_width;
4064
- $crop_height_orig = $crop_height;
4065
- $crop_factor_x = $crop_width / $crop_final_width;
4066
- $crop_factor_y = $crop_height / $crop_final_height;
4067
- $crop_ratio_x = $crop_width / $width;
4068
- $crop_ratio_y = $crop_height / $height;
4069
- if ($algo == 'adapt') {
4070
- // XXX not sure about this...don't use for now
4071
- # $crop_width = (int) round($width * $crop_factor_x);
4072
- # $crop_height = (int) round($height * $crop_factor_y);
4073
- } else {
4074
- if ($algo == 'shrink') {
4075
- if ($crop_ratio_x < $crop_ratio_y) {
4076
- $crop_width = max($crop_width, $width);
4077
- $crop_height = (int) round($crop_width / $aspect_ratio);
4078
- } else {
4079
- $crop_height = max($crop_height, $height);
4080
- $crop_width = (int) round($crop_height * $aspect_ratio);
4081
- }
4082
- if ($crop_width == $crop_width_orig - 1) {
4083
- $crop_width = $crop_width_orig;
4084
- }
4085
- if ($crop_height == $crop_height_orig - 1) {
4086
- $crop_height = $crop_height_orig;
4087
- }
4088
- }
4089
- }
4090
- $crop_diff_x = (int) round(($crop_width_orig - $crop_width) / 2);
4091
- $crop_diff_y = (int) round(($crop_height_orig - $crop_height) / 2);
4092
- $crop_x += $crop_diff_x;
4093
- $crop_y += $crop_diff_y;
4094
- $crop_max_x = $crop_x + $crop_width;
4095
- $crop_max_y = $crop_y + $crop_height;
4096
- // Check if we're overflowing borders
4097
- //
4098
- if ($crop_x < 0) {
4099
- $crop_x = 0;
4100
- } else {
4101
- if ($crop_max_x > $original_width) {
4102
- $crop_x -= $crop_max_x - $original_width;
4103
- }
4104
  }
4105
- if ($crop_y < 0) {
4106
- $crop_y = 0;
4107
- } else {
4108
- if ($crop_max_y > $original_height) {
4109
- $crop_y -= $crop_max_y - $original_height;
4110
- }
4111
  }
 
 
 
 
 
4112
  } else {
4113
- if ($orig_ratio_x < $orig_ratio_y) {
4114
- $crop_width = $original_width;
4115
- $crop_height = (int) round($height * $orig_ratio_x);
4116
- } else {
4117
- $crop_height = $original_height;
4118
- $crop_width = (int) round($width * $orig_ratio_y);
4119
- }
4120
- if ($crop_width == $width - 1) {
4121
- $crop_width = $width;
4122
- }
4123
- if ($crop_height == $height - 1) {
4124
- $crop_height = $height;
4125
  }
4126
- $crop_x = (int) round(($original_width - $crop_width) / 2);
4127
- $crop_y = (int) round(($original_height - $crop_height) / 2);
4128
  }
4129
- $result['crop_area'] = array('x' => $crop_x, 'y' => $crop_y, 'width' => $crop_width, 'height' => $crop_height);
4130
- } else {
4131
- // Just constraint dimensions to ensure there's no stretching or deformations
4132
- list($width, $height) = wp_constrain_dimensions($original_width, $original_height, $width, $height);
4133
  }
4134
  }
4135
- $result['width'] = $width;
4136
- $result['height'] = $height;
4137
- $result['quality'] = $quality;
4138
- $real_width = $width;
4139
- $real_height = $height;
4140
- if ($rotation && in_array(abs($rotation), array(90, 270))) {
4141
- $real_width = $height;
4142
- $real_height = $width;
4143
  }
4144
- if ($reflection) {
4145
- // default for nextgen was 40%, this is used in generate_image_clone as well
4146
- $reflection_amount = 40;
4147
- // Note, round() would probably be best here but using the same code that C_NggLegacy_Thumbnail uses for compatibility
4148
- $reflection_height = intval($real_height * ($reflection_amount / 100));
4149
- $real_height = $real_height + $reflection_height;
 
 
 
 
 
 
 
 
 
 
4150
  }
4151
- $result['real_width'] = $real_width;
4152
- $result['real_height'] = $real_height;
4153
  }
4154
- return $result;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4155
  }
4156
  /**
4157
- * Generates a specific size for an image
4158
- * @param int|object|C_Image $image
4159
- * @param string $size
4160
- * @param array|null $params (optional)
4161
- * @param bool $skip_defaults (optional)
4162
- * @return bool|object
4163
  */
4164
- function generate_image_size($image, $size, $params = null, $skip_defaults = false)
4165
  {
4166
- $retval = FALSE;
4167
- // Get the image entity
4168
- if (is_numeric($image)) {
4169
- $image = $this->object->_image_mapper->find($image);
 
 
4170
  }
4171
- // Ensure we have a valid image
4172
- if ($image) {
4173
- $params = $this->object->get_image_size_params($image, $size, $params, $skip_defaults);
4174
- $settings = C_NextGen_Settings::get_instance();
4175
- // Get the image filename
4176
- $filename = $this->object->get_image_abspath($image, 'original');
4177
- $thumbnail = null;
4178
- if ($size == 'full' && $settings->imgBackup == 1) {
4179
- // XXX change this? 'full' should be the resized path and 'original' the _backup path
4180
- $backup_path = $this->object->get_backup_abspath($image);
4181
- if (!@file_exists($backup_path)) {
4182
- @copy($filename, $backup_path);
4183
- }
4184
- }
4185
- // Generate the thumbnail using WordPress
4186
- $existing_image_abpath = $this->object->get_image_abspath($image, $size);
4187
- $existing_image_dir = dirname($existing_image_abpath);
4188
- wp_mkdir_p($existing_image_dir);
4189
- $clone_path = $existing_image_abpath;
4190
- $thumbnail = $this->object->generate_image_clone($filename, $clone_path, $params);
4191
- // We successfully generated the thumbnail
4192
- if ($thumbnail != null) {
4193
- $clone_path = $thumbnail->fileName;
4194
- if (function_exists('getimagesize')) {
4195
- $dimensions = getimagesize($clone_path);
4196
- } else {
4197
- $dimensions = array($params['width'], $params['height']);
4198
- }
4199
- if (!isset($image->meta_data)) {
4200
- $image->meta_data = array();
4201
- }
4202
- $size_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'filename' => M_I18n::mb_basename($clone_path), 'generated' => microtime());
4203
- if (isset($params['crop_frame'])) {
4204
- $size_meta['crop_frame'] = $params['crop_frame'];
4205
- }
4206
- $image->meta_data[$size] = $size_meta;
4207
- if ($size == 'full') {
4208
- $image->meta_data['width'] = $size_meta['width'];
4209
- $image->meta_data['height'] = $size_meta['height'];
4210
- }
4211
- $retval = $this->object->_image_mapper->save($image);
4212
- do_action('ngg_generated_image', $image, $size, $params);
4213
- if ($retval == 0) {
4214
- $retval = false;
4215
- }
4216
- if ($retval) {
4217
- $retval = $thumbnail;
4218
- }
4219
- } else {
4220
- // Something went wrong. Thumbnail generation failed!
4221
- }
4222
  }
4223
- return $retval;
 
 
4224
  }
4225
- function generate_resized_image($image, $save = TRUE)
 
 
 
 
 
 
 
4226
  {
4227
- $image_abspath = $this->object->get_image_abspath($image, 'full');
4228
- $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full'));
4229
- if ($generated && $save) {
4230
- $this->object->update_image_dimension_metadata($image, $image_abspath);
 
 
4231
  }
4232
- if ($generated) {
4233
- $generated->destruct();
4234
  }
 
 
 
 
4235
  }
4236
- public function update_image_dimension_metadata($image, $image_abspath)
 
 
 
 
 
4237
  {
4238
- // Ensure that fullsize dimensions are added to metadata array
4239
- $dimensions = getimagesize($image_abspath);
4240
- $full_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'md5' => $this->object->get_image_checksum($image, 'full'));
4241
- if (!isset($image->meta_data) or is_string($image->meta_data) && strlen($image->meta_data) == 0 or is_bool($image->meta_data)) {
4242
- $image->meta_data = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4243
  }
4244
- $image->meta_data = array_merge($image->meta_data, $full_meta);
4245
- $image->meta_data['full'] = $full_meta;
4246
- // Don't forget to append the 'full' entry in meta_data in the db
4247
- $this->object->_image_mapper->save($image);
4248
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4249
  /**
4250
- * Most major browsers do not honor the Orientation meta found in EXIF. To prevent display issues we inspect
4251
- * the EXIF data and rotate the image so that the EXIF field is not necessary to display the image correctly.
4252
- * Note: generate_image_clone() will handle the removal of the Orientation tag inside the image EXIF.
4253
- * Note: This only handles single-dimension rotation; at the time this method was written there are no known
4254
- * camera manufacturers that both rotate and flip images.
4255
- * @param $image
4256
- * @param bool $save
4257
  */
4258
- public function correct_exif_rotation($image, $save = TRUE)
4259
  {
4260
- $image_abspath = $this->object->get_image_abspath($image, 'full');
4261
- // This method is necessary
4262
- if (!function_exists('exif_read_data')) {
4263
- return;
 
4264
  }
4265
- // We only need to continue if the Orientation tag is set
4266
- $exif = @exif_read_data($image_abspath, 'exif');
4267
- if (empty($exif['Orientation']) || $exif['Orientation'] == 1) {
4268
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4269
  }
4270
- $degree = 0;
4271
- if ($exif['Orientation'] == 3) {
4272
- $degree = 180;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4273
  }
4274
- if ($exif['Orientation'] == 6) {
4275
- $degree = 90;
 
4276
  }
4277
- if ($exif['Orientation'] == 8) {
4278
- $degree = 270;
 
4279
  }
4280
- $parameters = array('rotation' => $degree);
4281
- $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full', $parameters), $parameters);
4282
- if ($generated && $save) {
4283
- $this->object->update_image_dimension_metadata($image, $image_abspath);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4284
  }
4285
- if ($generated) {
4286
- $generated->destruct();
 
 
 
4287
  }
4288
  }
4289
  /**
4290
- * Generates a thumbnail for an image
4291
- * @param int|stdClass|C_Image $image
4292
- * @return bool
4293
  */
4294
- function generate_thumbnail($image, $params = null, $skip_defaults = false)
4295
  {
4296
- $sized_image = $this->object->generate_image_size($image, 'thumbnail', $params, $skip_defaults);
4297
- $retval = false;
4298
- if ($sized_image != null) {
4299
- $retval = true;
4300
- $sized_image->destruct();
 
 
 
 
 
 
 
 
4301
  }
4302
- return $retval;
4303
- }
4304
- }
4305
- /**
4306
- * Provides getter methods to C_Gallery_Storage for determining absolute paths, URL, etc
4307
- * @property C_Gallery_Storage $object
4308
- */
4309
- class Mixin_GalleryStorage_Base_Getters extends Mixin
4310
- {
4311
- static $gallery_abspath_cache = array();
4312
- static $image_abspath_cache = array();
4313
- static $image_url_cache = array();
4314
- /**
4315
- * Flushes the cache we use for path/url calculation for images
4316
- */
4317
- function flush_image_path_cache($image, $size)
4318
- {
4319
- $image = is_numeric($image) ? $image : $image->pid;
4320
- $key = strval($image) . $size;
4321
- unset(self::$image_abspath_cache[$key]);
4322
- unset(self::$image_url_cache[$key]);
4323
- }
4324
- /**
4325
- * Flushes the cache we use for path/url calculation for galleries
4326
- */
4327
- function flush_gallery_path_cache($gallery)
4328
- {
4329
- $gallery = is_numeric($gallery) ? $gallery : $gallery->gid;
4330
- unset(self::$gallery_abspath_cache[$gallery]);
4331
  }
4332
- /**
4333
- * Gets the id of an image, regardless of whether an integer
4334
- * or object was passed as an argument
4335
- * @param object|int $image_obj_or_id
4336
- * @return null|int
4337
- */
4338
- function _get_image_id($image_obj_or_id)
4339
  {
4340
- $retval = NULL;
4341
- $image_key = $this->object->_image_mapper->get_primary_key_column();
4342
- if (is_object($image_obj_or_id)) {
4343
- if (isset($image_obj_or_id->{$image_key})) {
4344
- $retval = $image_obj_or_id->{$image_key};
 
 
 
 
 
 
 
 
 
4345
  }
4346
- } elseif (is_numeric($image_obj_or_id)) {
4347
- $retval = $image_obj_or_id;
4348
  }
4349
- return $retval;
4350
- }
4351
- /**
4352
- * Gets the absolute path of the backup of an original image
4353
- * @param string $image
4354
- * @return null|string
4355
- */
4356
- function get_backup_abspath($image)
4357
- {
4358
- $retval = null;
4359
- if ($image_path = $this->object->get_image_abspath($image)) {
4360
- $retval = $image_path . '_backup';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4361
  }
4362
- return $retval;
4363
- }
4364
- function get_backup_dimensions($image)
4365
- {
4366
- return $this->object->get_image_dimensions($image, 'backup');
4367
  }
4368
- function get_backup_url($image)
4369
  {
4370
- return $this->object->get_image_url($image, 'backup');
4371
  }
4372
  /**
4373
- * Returns the absolute path to the cache directory of a gallery.
4374
- *
4375
- * Without the gallery parameter the legacy (pre 2.0) shared directory is returned.
4376
  *
4377
- * @param int|object|false|C_Gallery $gallery (optional)
4378
- * @return string Absolute path to cache directory
4379
  */
4380
- function get_cache_abspath($gallery = FALSE)
4381
  {
4382
- return path_join($this->object->get_gallery_abspath($gallery), 'cache');
 
 
 
 
 
 
 
 
4383
  }
4384
  /**
4385
- * Gets the absolute path where the full-sized image is stored
4386
- * @param int|object $image
4387
- * @return null|string
4388
  */
4389
- function get_full_abspath($image)
4390
  {
4391
- return $this->object->get_image_abspath($image, 'full');
4392
  }
4393
  /**
4394
- * Alias to get_image_dimensions()
4395
- * @param int|object $image
4396
- * @return array
4397
  */
4398
- function get_full_dimensions($image)
4399
  {
4400
- return $this->object->get_image_dimensions($image, 'full');
4401
  }
4402
  /**
4403
- * Alias to get_image_html()
4404
- * @param int|object $image
4405
- * @return string
 
 
4406
  */
4407
- function get_full_html($image)
4408
  {
4409
- return $this->object->get_image_html($image, 'full');
 
 
 
 
 
4410
  }
4411
  /**
4412
- * Alias for get_original_url()
4413
  *
4414
- * @param int|stdClass|C_Image $image
4415
- * @return string
 
4416
  */
4417
- function get_full_url($image)
4418
- {
4419
- return $this->object->get_image_url($image, 'full');
4420
- }
4421
- function get_gallery_root()
4422
- {
4423
- return wp_normalize_path(C_Fs::get_instance()->get_document_root('galleries'));
4424
- }
4425
- function _get_computed_gallery_abspath($gallery)
4426
  {
4427
- $retval = NULL;
4428
- $gallery_root = $this->get_gallery_root();
4429
- // Get the gallery entity from the database
4430
- if ($gallery) {
4431
- if (is_numeric($gallery)) {
4432
- $gallery = $this->object->_gallery_mapper->find($gallery);
4433
- }
4434
- }
4435
- // It just doesn't exist
4436
- if (!$gallery) {
4437
- return $retval;
4438
- }
4439
- // We we have a gallery, determine it's path
4440
- if ($gallery) {
4441
- if (isset($gallery->path)) {
4442
- $retval = $gallery->path;
4443
- } elseif (isset($gallery->slug)) {
4444
- $basepath = wp_normalize_path(C_NextGen_Settings::get_instance()->gallerypath);
4445
- $retval = path_join($basepath, $this->object->sanitize_directory_name(sanitize_title($gallery->slug)));
4446
- }
4447
- // Normalize the gallery path. If the gallery path starts with /wp-content, and
4448
- // NGG_GALLERY_ROOT_TYPE is set to 'content', then we need to strip out the /wp-content
4449
- // from the start of the gallery path
4450
- if (NGG_GALLERY_ROOT_TYPE === 'content') {
4451
- $retval = preg_replace("#^/?wp-content#", "", $retval);
4452
- }
4453
- // Ensure that the path is absolute
4454
- if (strpos($retval, $gallery_root) !== 0) {
4455
- // path_join() behaves funny - if the second argument starts with a slash,
4456
- // it won't join the two paths together
4457
- $retval = preg_replace("#^/#", "", $retval);
4458
- $retval = path_join($gallery_root, $retval);
4459
- }
4460
- $retval = wp_normalize_path($retval);
4461
  }
4462
- return $retval;
4463
  }
4464
  /**
4465
- * Get the abspath to the gallery folder for the given gallery
4466
- * The gallery may or may not already be persisted
4467
- * @param int|object|C_Gallery $gallery
4468
- * @return string
 
4469
  */
4470
- function get_gallery_abspath($gallery)
4471
- {
4472
- $gallery_id = is_numeric($gallery) ? $gallery : (is_object($gallery) && isset($gallery->gid) ? $gallery->gid : NULL);
4473
- if (!$gallery_id || !isset(self::$gallery_abspath_cache[$gallery_id])) {
4474
- self::$gallery_abspath_cache[$gallery_id] = $this->object->_get_computed_gallery_abspath($gallery);
4475
- }
4476
- return self::$gallery_abspath_cache[$gallery_id];
4477
- }
4478
- function get_gallery_relpath($gallery)
4479
  {
4480
- // Special hack for home.pl: their document root is just '/'
4481
- $root = $this->object->get_gallery_root();
4482
- if ($root === '/') {
4483
- return $this->get_gallery_abspath($gallery);
4484
  }
4485
- return str_replace($this->object->get_gallery_root(), '', $this->get_gallery_abspath($gallery));
 
 
4486
  }
4487
  /**
4488
- * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image.
4489
- * @param int|object $image
4490
- * @param string $size (optional) Default = full
4491
- * @return string
4492
  */
4493
- function _get_computed_image_abspath($image, $size = 'full', $check_existance = FALSE)
4494
  {
4495
- $retval = NULL;
4496
- $fs = C_Fs::get_instance();
4497
- // If we have the id, get the actual image entity
4498
- if (is_numeric($image)) {
4499
- $image = $this->object->_image_mapper->find($image);
4500
- }
4501
- // Ensure we have the image entity - user could have passed in an
4502
- // incorrect id
4503
- if (is_object($image)) {
4504
- if ($gallery_path = $this->object->get_gallery_abspath($image->galleryid)) {
4505
- $folder = $prefix = $size;
4506
- switch ($size) {
4507
- # Images are stored in the associated gallery folder
4508
- case 'full':
4509
- $retval = path_join($gallery_path, $image->filename);
4510
- break;
4511
- case 'backup':
4512
- $retval = path_join($gallery_path, $image->filename . '_backup');
4513
- if (!@file_exists($retval)) {
4514
- $retval = path_join($gallery_path, $image->filename);
4515
- }
4516
- break;
4517
- case 'thumbnail':
4518
- $size = 'thumbnail';
4519
- $folder = 'thumbs';
4520
- $prefix = 'thumbs';
4521
- // deliberately no break here
4522
- default:
4523
- // NGG 2.0 stores relative filenames in the meta data of
4524
- // an image. It does this because it uses filenames
4525
- // that follow conventional WordPress naming scheme.
4526
- $image_path = NULL;
4527
- $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
4528
- if (isset($image->meta_data) && isset($image->meta_data[$size]) && isset($image->meta_data[$size]['filename'])) {
4529
- if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) {
4530
- $image_path = path_join($this->object->get_cache_abspath($image->galleryid), $image->meta_data[$size]['filename']);
4531
- } else {
4532
- $image_path = path_join($gallery_path, $folder);
4533
- $image_path = path_join($image_path, $image->meta_data[$size]['filename']);
4534
- }
4535
- } else {
4536
- if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) {
4537
- $params = $dynthumbs->get_params_from_name($size, true);
4538
- $image_path = path_join($this->object->get_cache_abspath($image->galleryid), $dynthumbs->get_image_name($image, $params));
4539
- // Filename is not found in meta, nor dynamic
4540
- } else {
4541
- $image_path = path_join($gallery_path, $folder);
4542
- $image_path = path_join($image_path, "{$prefix}_{$image->filename}");
4543
- }
4544
- }
4545
- $retval = $image_path;
4546
- break;
4547
- }
4548
- }
4549
- }
4550
- if ($retval && $check_existance && !@file_exists($retval)) {
4551
- $retval = NULL;
4552
  }
4553
- return $retval;
4554
  }
4555
  /**
4556
- * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image.
4557
- * @param int|object $image
4558
- * @param string $size (optional) Default = full
4559
- * @param bool $check_existance (optional) Default = false
4560
- * @return string
4561
  */
4562
- function get_image_abspath($image, $size = 'full', $check_existance = FALSE)
4563
- {
4564
- $image_id = is_numeric($image) ? $image : $image->pid;
4565
- $size = $this->object->normalize_image_size_name($size);
4566
- $key = strval($image_id) . $size;
4567
- if ($check_existance || !isset(self::$image_abspath_cache[$key])) {
4568
- $retval = $this->object->_get_computed_image_abspath($image, $size, $check_existance);
4569
- self::$image_abspath_cache[$key] = $retval;
4570
- }
4571
- $retval = self::$image_abspath_cache[$key];
4572
- return $retval;
4573
- }
4574
- function get_image_checksum($image, $size = 'full')
4575
  {
4576
- $retval = NULL;
4577
- if ($image_abspath = $this->get_image_abspath($image, $size, TRUE)) {
4578
- $retval = md5_file($image_abspath);
4579
  }
4580
- return $retval;
4581
  }
4582
  /**
4583
- * Gets the dimensions for a particular-sized image
4584
  *
4585
- * @param int|object $image
4586
- * @param string $size
4587
- * @return null|array
4588
  */
4589
- function get_image_dimensions($image, $size = 'full')
4590
- {
4591
- $retval = NULL;
4592
- // If an image id was provided, get the entity
4593
- if (is_numeric($image)) {
4594
- $image = $this->object->_image_mapper->find($image);
4595
- }
4596
- // Ensure we have a valid image
4597
- if ($image) {
4598
- $size = $this->normalize_image_size_name($size);
4599
- if (!$size) {
4600
- $size = 'full';
4601
- }
4602
- // Image dimensions are stored in the $image->meta_data
4603
- // property for all implementations
4604
- if (isset($image->meta_data) && isset($image->meta_data[$size])) {
4605
- $retval = $image->meta_data[$size];
4606
- } else {
4607
- $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
4608
- $abspath = $this->object->get_image_abspath($image, $size, TRUE);
4609
- if ($abspath) {
4610
- $dims = @getimagesize($abspath);
4611
- if ($dims) {
4612
- $retval['width'] = $dims[0];
4613
- $retval['height'] = $dims[1];
4614
- }
4615
- } elseif ($size == 'backup') {
4616
- $retval = $this->object->get_image_dimensions($image, 'full');
4617
- }
4618
- if (!$retval && $dynthumbs && $dynthumbs->is_size_dynamic($size)) {
4619
- $new_dims = $this->object->calculate_image_size_dimensions($image, $size);
4620
- $retval = array('width' => $new_dims['real_width'], 'height' => $new_dims['real_height']);
4621
- }
4622
- }
4623
- }
4624
- return $retval;
4625
- }
4626
- function get_image_format_list()
4627
  {
4628
- $format_list = array(IMAGETYPE_GIF => 'gif', IMAGETYPE_JPEG => 'jpg', IMAGETYPE_PNG => 'png');
4629
- return $format_list;
 
 
 
 
 
 
 
4630
  }
4631
  /**
4632
- * Gets the HTML for an image
4633
- * @param int|object $image
4634
- * @param string $size
4635
- * @param array $attributes (optional)
4636
- * @return string
4637
  */
4638
- function get_image_html($image, $size = 'full', $attributes = array())
4639
  {
4640
- $retval = "";
4641
- if (is_numeric($image)) {
4642
- $image = $this->object->_image_mapper->find($image);
4643
  }
4644
- if ($image) {
4645
- // Set alt text if not already specified
4646
- if (!isset($attributes['alttext'])) {
4647
- $attributes['alt'] = esc_attr($image->alttext);
4648
- }
4649
- // Set the title if not already set
4650
- if (!isset($attributes['title'])) {
4651
- $attributes['title'] = esc_attr($image->alttext);
4652
- }
4653
- // Set the dimensions if not set already
4654
- if (!isset($attributes['width']) or !isset($attributes['height'])) {
4655
- $dimensions = $this->object->get_image_dimensions($image, $size);
4656
- if (!isset($attributes['width'])) {
4657
- $attributes['width'] = $dimensions['width'];
4658
- }
4659
- if (!isset($attributes['height'])) {
4660
- $attributes['height'] = $dimensions['height'];
4661
- }
4662
- }
4663
- // Set the url if not already specified
4664
- if (!isset($attributes['src'])) {
4665
- $attributes['src'] = $this->object->get_image_url($image, $size);
4666
- }
4667
- // Format attributes
4668
- $attribs = array();
4669
- foreach ($attributes as $attrib => $value) {
4670
- $attribs[] = "{$attrib}=\"{$value}\"";
4671
- }
4672
- $attribs = implode(" ", $attribs);
4673
- // Return HTML string
4674
- $retval = "<img {$attribs} />";
4675
  }
4676
- return $retval;
 
 
 
 
 
4677
  }
4678
- function _get_computed_image_url($image, $size = 'full')
 
 
 
 
 
 
 
4679
  {
4680
- $retval = NULL;
4681
- $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
4682
- // Get the image abspath
4683
- $image_abspath = $this->object->get_image_abspath($image, $size);
4684
- if ($dynthumbs->is_size_dynamic($size) && !file_exists($image_abspath)) {
4685
- if (defined('NGG_DISABLE_DYNAMIC_IMG_URLS') && constant('NGG_DISABLE_DYNAMIC_IMG_URLS')) {
4686
- $params = array('watermark' => false, 'reflection' => false, 'crop' => true);
4687
- $result = $this->generate_image_size($image, $size, $params);
4688
- if ($result) {
4689
- $image_abspath = $this->object->get_image_abspath($image, $size);
4690
- }
4691
- } else {
4692
- return NULL;
4693
- }
4694
  }
4695
- // Assuming we have an abspath, we can translate that to a url
4696
- if ($image_abspath) {
4697
- // Replace the gallery root with the proper url segment
4698
- $gallery_root = preg_quote($this->get_gallery_root(), '#');
4699
- $image_uri = preg_replace("#^{$gallery_root}#", "", $image_abspath);
4700
- // Url encode each uri segment
4701
- $segments = explode("/", $image_uri);
4702
- $segments = array_map('rawurlencode', $segments);
4703
- $image_uri = preg_replace("#^/#", "", implode("/", $segments));
4704
- // Join gallery root and image uri
4705
- $gallery_root = trailingslashit(NGG_GALLERY_ROOT_TYPE == 'site' ? site_url() : WP_CONTENT_URL);
4706
- $gallery_root = is_ssl() ? str_replace('http:', 'https:', $gallery_root) : $gallery_root;
4707
- $retval = $gallery_root . $image_uri;
4708
  }
4709
- return $retval;
 
 
 
 
 
 
 
 
 
 
 
4710
  }
4711
- function normalize_image_size_name($size = 'full')
 
 
 
 
 
4712
  {
4713
- switch ($size) {
4714
- case 'full':
4715
- case 'original':
4716
- case 'image':
4717
- case 'orig':
4718
- case 'resized':
4719
- $size = 'full';
4720
- break;
4721
- case 'thumbnails':
4722
- case 'thumbnail':
4723
- case 'thumb':
4724
- case 'thumbs':
4725
- $size = 'thumbnail';
4726
- break;
4727
  }
4728
- return $size;
 
 
 
 
 
 
 
 
 
 
 
4729
  }
4730
  /**
4731
- * Gets the url of a particular-sized image
4732
- * @param int|object $image
4733
- * @param string $size
4734
- * @return string
4735
  */
4736
- function get_image_url($image, $size = 'full')
4737
  {
4738
- $retval = NULL;
4739
- $image_id = is_numeric($image) ? $image : $image->pid;
4740
- $key = strval($image_id) . $size;
4741
- $success = TRUE;
4742
- if (!isset(self::$image_url_cache[$key])) {
4743
- $url = $this->object->_get_computed_image_url($image, $size);
4744
- if ($url) {
4745
- self::$image_url_cache[$key] = $url;
4746
- $success = TRUE;
4747
- } else {
4748
- $success = FALSE;
4749
- }
4750
  }
4751
- if ($success) {
4752
- $retval = self::$image_url_cache[$key];
 
 
 
 
 
 
 
 
 
4753
  } else {
4754
- $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
4755
- if ($dynthumbs->is_size_dynamic($size)) {
4756
- $params = $dynthumbs->get_params_from_name($size);
4757
- $retval = $dynthumbs->get_image_url($image, $params);
4758
- }
4759
  }
4760
- return apply_filters('ngg_get_image_url', $retval, $image, $size);
 
 
 
 
4761
  }
4762
  /**
4763
- * Returns the named sizes available for images
4764
- * @return array
 
 
 
 
4765
  */
4766
- function get_image_sizes($image = FALSE)
4767
  {
4768
- $retval = array('full', 'thumbnail');
4769
- if (is_numeric($image)) {
4770
- $image = C_Image_Mapper::get_instance()->find($image);
4771
  }
4772
- if ($image) {
4773
- if ($image->meta_data) {
4774
- $meta_data = is_object($image->meta_data) ? get_object_vars($image->meta_data) : $image->meta_data;
4775
- foreach ($meta_data as $key => $value) {
4776
- if (is_array($value) && isset($value['width']) && !in_array($key, $retval)) {
4777
- $retval[] = $key;
4778
- }
4779
- }
4780
- }
4781
  }
4782
- return $retval;
4783
- }
4784
- function get_image_size_params($image, $size, $params = array(), $skip_defaults = false)
4785
- {
4786
- // Get the image entity
4787
- if (is_numeric($image)) {
4788
- $image = $this->object->_image_mapper->find($image);
4789
  }
4790
- $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
4791
- if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) {
4792
- $named_params = $dynthumbs->get_params_from_name($size, true);
4793
- if (!$params) {
4794
- $params = array();
4795
- }
4796
- $params = array_merge($params, $named_params);
4797
  }
4798
- $params = apply_filters('ngg_get_image_size_params', $params, $size, $image);
4799
- // Ensure we have a valid image
4800
- if ($image) {
4801
- $settings = C_NextGen_Settings::get_instance();
4802
- if (!$skip_defaults) {
4803
- // Get default settings
4804
- if ($size == 'full') {
4805
- if (!isset($params['quality'])) {
4806
- $params['quality'] = $settings->imgQuality;
4807
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4808
  } else {
4809
- if (!isset($params['crop'])) {
4810
- $params['crop'] = $settings->thumbfix;
4811
- }
4812
- if (!isset($params['quality'])) {
4813
- $params['quality'] = $settings->thumbquality;
4814
- }
4815
  }
4816
- }
4817
- // width and height when omitted make generate_image_clone create a clone with original size, so try find defaults regardless of $skip_defaults
4818
- if (!isset($params['width']) || !isset($params['height'])) {
4819
- // First test if this is a "known" image size, i.e. if we store these sizes somewhere when users re-generate these sizes from the UI...this is required to be compatible with legacy
4820
- // try the 2 default built-in sizes, first thumbnail...
4821
- if ($size == 'thumbnail') {
4822
- if (!isset($params['width'])) {
4823
- $params['width'] = $settings->thumbwidth;
4824
- }
4825
- if (!isset($params['height'])) {
4826
- $params['height'] = $settings->thumbheight;
4827
- }
4828
  } else {
4829
- if ($size == 'full') {
4830
- if (!isset($params['width'])) {
4831
- if ($settings->imgAutoResize) {
4832
- $params['width'] = $settings->imgWidth;
4833
- }
4834
- }
4835
- if (!isset($params['height'])) {
4836
- if ($settings->imgAutoResize) {
4837
- $params['height'] = $settings->imgHeight;
4838
- }
4839
- }
4840
- } else {
4841
- if (isset($image->meta_data) && isset($image->meta_data[$size])) {
4842
- $dimensions = $image->meta_data[$size];
4843
- if (!isset($params['width'])) {
4844
- $params['width'] = $dimensions['width'];
4845
- }
4846
- if (!isset($params['height'])) {
4847
- $params['height'] = $dimensions['height'];
4848
- }
4849
- }
4850
- }
4851
- }
4852
- }
4853
- if (!isset($params['crop_frame'])) {
4854
- $crop_frame_size_name = 'thumbnail';
4855
- if (isset($image->meta_data[$size]['crop_frame'])) {
4856
- $crop_frame_size_name = $size;
4857
- }
4858
- if (isset($image->meta_data[$crop_frame_size_name]['crop_frame'])) {
4859
- $params['crop_frame'] = $image->meta_data[$crop_frame_size_name]['crop_frame'];
4860
- if (!isset($params['crop_frame']['final_width'])) {
4861
- $params['crop_frame']['final_width'] = $image->meta_data[$crop_frame_size_name]['width'];
4862
- }
4863
- if (!isset($params['crop_frame']['final_height'])) {
4864
- $params['crop_frame']['final_height'] = $image->meta_data[$crop_frame_size_name]['height'];
4865
- }
4866
- }
4867
- } else {
4868
- if (!isset($params['crop_frame']['final_width'])) {
4869
- $params['crop_frame']['final_width'] = $params['width'];
4870
  }
4871
- if (!isset($params['crop_frame']['final_height'])) {
4872
- $params['crop_frame']['final_height'] = $params['height'];
 
 
 
 
 
4873
  }
4874
- }
4875
  }
4876
- return $params;
4877
- }
4878
- /**
4879
- * An alias for get_full_abspath()
4880
- * @param int|object $image
4881
- * @param bool $check_existance
4882
- * @return null|string
4883
- */
4884
- function get_original_abspath($image, $check_existance = FALSE)
4885
- {
4886
- return $this->object->get_image_abspath($image, 'full', $check_existance);
4887
- }
4888
- /**
4889
- * Alias to get_image_dimensions()
4890
- * @param int|object $image
4891
- * @return array
4892
- */
4893
- function get_original_dimensions($image)
4894
- {
4895
- return $this->object->get_image_dimensions($image, 'full');
4896
- }
4897
- /**
4898
- * Alias to get_image_html()
4899
- * @param int|object $image
4900
- * @return string
4901
- */
4902
- function get_original_html($image)
4903
- {
4904
- return $this->object->get_image_html($image, 'full');
4905
  }
4906
  /**
4907
- * Gets the url to the original-sized image
4908
- * @param int|stdClass|C_Image $image
4909
- * @param bool $check_existance (optional)
4910
- * @return string
 
4911
  */
4912
- function get_original_url($image, $check_existance = FALSE)
4913
  {
4914
- return $this->object->get_image_url($image, 'full', $check_existance);
 
 
 
 
 
 
 
 
4915
  }
4916
  /**
4917
- * @param object|bool $gallery (optional)
4918
- * @return string
 
 
 
 
 
4919
  */
4920
- function get_upload_abspath($gallery = FALSE)
4921
  {
4922
- // Base upload path
4923
- $retval = C_NextGen_Settings::get_instance()->gallerypath;
4924
- $fs = C_Fs::get_instance();
4925
- // If a gallery has been specified, then we'll
4926
- // append the slug
4927
- if ($gallery) {
4928
- $retval = $this->get_gallery_abspath($gallery);
 
 
 
 
 
 
 
 
 
4929
  }
4930
- // We need to make this an absolute path
4931
- if (strpos($retval, $fs->get_document_root('gallery')) !== 0) {
4932
- $retval = rtrim($fs->join_paths($fs->get_document_root('gallery'), $retval), "/\\");
 
 
 
 
 
 
 
 
4933
  }
4934
- // Convert slashes
4935
- return wp_normalize_path($retval);
 
 
4936
  }
4937
  /**
4938
- * Gets the upload path, optionally for a particular gallery
4939
- * @param int|C_Gallery|object|false $gallery (optional)
4940
- * @return string
 
 
4941
  */
4942
- function get_upload_relpath($gallery = FALSE)
4943
  {
4944
- $fs = C_Fs::get_instance();
4945
- $retval = str_replace($fs->get_document_root('gallery'), '', $this->object->get_upload_abspath($gallery));
4946
- return '/' . wp_normalize_path(ltrim($retval, "/"));
 
 
 
 
 
 
4947
  }
4948
- }
4949
- /**
4950
- * Provides the basic methods of gallery management to C_Gallery_Storage
4951
- * @property C_Gallery_Storage $object
4952
- */
4953
- class Mixin_GalleryStorage_Base_Management extends Mixin
4954
- {
4955
  /**
4956
- * Set correct file permissions (taken from wp core). Should be called
4957
- * after writing any file
4958
  *
4959
- * @class nggAdmin
4960
- * @param string $filename
4961
- * @return bool $result
4962
  */
4963
- function _chmod($filename = '')
4964
- {
4965
- $stat = @stat(dirname($filename));
4966
- $perms = $stat['mode'] & 0666;
4967
- // Remove execute bits for files
4968
- if (@chmod($filename, $perms)) {
4969
- return TRUE;
4970
- }
4971
- return FALSE;
4972
- }
4973
- function _delete_gallery_directory($abspath)
4974
  {
4975
- // Remove all image files and purge all empty directories left over
4976
- $iterator = new DirectoryIterator($abspath);
4977
- // Only delete image files! Other files may be stored incorrectly but it's not our place to delete them
4978
- $removable_extensions = apply_filters('ngg_allowed_file_types', array('jpeg', 'jpg', 'png', 'gif'));
4979
- foreach ($removable_extensions as $extension) {
4980
- $removable_extensions[] = $extension . '_backup';
4981
- }
4982
- foreach ($iterator as $file) {
4983
- if (in_array($file->getBasename(), array('.', '..'))) {
4984
- continue;
4985
- } elseif ($file->isFile() || $file->isLink()) {
4986
- $extension = strtolower(pathinfo($file->getPathname(), PATHINFO_EXTENSION));
4987
- if (in_array($extension, $removable_extensions, TRUE)) {
4988
- @unlink($file->getPathname());
4989
- }
4990
- } elseif ($file->isDir()) {
4991
- $this->object->_delete_gallery_directory($file->getPathname());
4992
- }
4993
- }
4994
- // DO NOT remove directories that still have files in them. Note: '.' and '..' are included with getSize()
4995
- $empty = TRUE;
4996
- foreach ($iterator as $file) {
4997
- if (in_array($file->getBasename(), array('.', '..'))) {
4998
- continue;
4999
- }
5000
- $empty = FALSE;
5001
- }
5002
- if ($empty) {
5003
- @rmdir($iterator->getPath());
5004
- }
5005
  }
5006
  /**
5007
- * Backs up an image file
5008
  *
5009
- * @param int|object $image
5010
- * @param bool $save
5011
  * @return bool
5012
  */
5013
- function backup_image($image, $save = TRUE)
5014
  {
5015
- $retval = FALSE;
5016
- $image_path = $this->object->get_image_abspath($image);
5017
- if ($image_path && @file_exists($image_path)) {
5018
- $retval = copy($image_path, $this->object->get_backup_abspath($image));
5019
- // Store the dimensions of the image
5020
- if (function_exists('getimagesize')) {
5021
- $mapper = C_Image_Mapper::get_instance();
5022
- if (!is_object($image)) {
5023
- $image = $mapper->find($image);
5024
- }
5025
- if ($image) {
5026
- if (!property_exists($image, 'meta_data')) {
5027
- $image->meta_data = array();
5028
- }
5029
- $dimensions = getimagesize($image_path);
5030
- $image->meta_data['backup'] = array('filename' => basename($image_path), 'width' => $dimensions[0], 'height' => $dimensions[1], 'generated' => microtime());
5031
- if ($save) {
5032
- $mapper->save($image);
5033
- }
5034
- }
5035
- }
5036
  }
5037
- return $retval;
5038
- }
5039
- /**
5040
- * @param C_Image[]|int[] $images
5041
- * @param C_Gallery|int $dst_gallery
5042
- * @return int[]
5043
- */
5044
- function copy_images($images, $dst_gallery)
5045
- {
5046
- $retval = array();
5047
- // Ensure that the image ids we have are valid
5048
- $image_mapper = C_Image_Mapper::get_instance();
5049
- foreach ($images as $image) {
5050
- if (is_numeric($image)) {
5051
- $image = $image_mapper->find($image);
5052
- }
5053
- if ($image_abspath = $this->object->get_image_abspath($image)) {
5054
- // Import the image; this will copy the main file
5055
- $new_image_id = $this->object->import_image_file($dst_gallery, $image_abspath, $image->filename);
5056
- if ($new_image_id) {
5057
- // Copy the properties of the old image
5058
- $new_image = $image_mapper->find($new_image_id);
5059
- foreach (get_object_vars($image) as $key => $value) {
5060
- if (in_array($key, array('pid', 'galleryid', 'meta_data', 'filename', 'sortorder', 'extras_post_id'))) {
5061
- continue;
5062
  }
5063
- $new_image->{$key} = $value;
5064
  }
5065
- $image_mapper->save($new_image);
5066
- // Copy tags
5067
- $tags = wp_get_object_terms($image->pid, 'ngg_tag', 'fields=ids');
5068
- $tags = array_map('intval', $tags);
5069
- wp_set_object_terms($new_image_id, $tags, 'ngg_tag', true);
5070
- // Copy all of the generated versions (resized versions, watermarks, etc)
5071
- foreach ($this->object->get_image_sizes($image) as $named_size) {
5072
- if (in_array($named_size, array('full', 'thumbnail'))) {
5073
- continue;
5074
- }
5075
- $old_abspath = $this->object->get_image_abspath($image, $named_size);
5076
- $new_abspath = $this->object->get_image_abspath($new_image, $named_size);
5077
- if (is_array(@stat($old_abspath))) {
5078
- $new_dir = dirname($new_abspath);
5079
- // Ensure the target directory exists
5080
- if (@stat($new_dir) === FALSE) {
5081
- wp_mkdir_p($new_dir);
5082
- }
5083
- @copy($old_abspath, $new_abspath);
5084
  }
5085
  }
5086
- // Mark as done
5087
- $retval[] = $new_image_id;
5088
  }
5089
- }
5090
- }
5091
- return $retval;
5092
- }
5093
- /**
5094
- * Moves images from to another gallery
5095
- * @param array $images
5096
- * @param int|object $gallery
5097
- * @return int[]
5098
- */
5099
- function move_images($images, $gallery)
5100
- {
5101
- $retval = $this->object->copy_images($images, $gallery);
5102
- if ($images) {
5103
- foreach ($images as $image_id) {
5104
- $this->object->delete_image($image_id);
5105
- }
5106
  }
5107
- return $retval;
 
 
 
 
5108
  }
5109
  /**
5110
- * @param string $abspath
5111
- * @return bool
 
5112
  */
5113
- function delete_directory($abspath)
5114
  {
5115
- $retval = FALSE;
5116
- if (@file_exists($abspath)) {
5117
- $files = scandir($abspath);
5118
- array_shift($files);
5119
- array_shift($files);
5120
- foreach ($files as $file) {
5121
- $file_abspath = implode(DIRECTORY_SEPARATOR, array(rtrim($abspath, "/\\"), $file));
5122
- if (is_dir($file_abspath)) {
5123
- $this->object->delete_directory($file_abspath);
5124
- } else {
5125
- unlink($file_abspath);
5126
- }
5127
- }
5128
- rmdir($abspath);
5129
- $retval = @file_exists($abspath);
5130
  }
5131
- return $retval;
5132
  }
5133
- function delete_gallery($gallery)
 
 
 
 
 
 
 
5134
  {
5135
- $fs = C_Fs::get_instance();
5136
- $safe_dirs = array(DIRECTORY_SEPARATOR, $fs->get_document_root('plugins'), $fs->get_document_root('plugins_mu'), $fs->get_document_root('templates'), $fs->get_document_root('stylesheets'), $fs->get_document_root('content'), $fs->get_document_root('galleries'), $fs->get_document_root());
5137
- $abspath = $this->object->get_gallery_abspath($gallery);
5138
- if ($abspath && file_exists($abspath) && !in_array(stripslashes($abspath), $safe_dirs)) {
5139
- $this->object->_delete_gallery_directory($abspath);
 
 
5140
  }
 
 
 
 
 
 
 
 
5141
  }
5142
- function delete_image($image, $size = FALSE)
 
 
 
 
 
 
 
 
 
5143
  {
5144
- $retval = FALSE;
5145
- // Ensure that we have the image entity
5146
- if (is_numeric($image)) {
5147
- $image = $this->object->_image_mapper->find($image);
5148
  }
5149
- if ($image) {
5150
- $image_id = $image->{$image->id_field};
5151
- do_action('ngg_delete_image', $image_id, $size);
5152
- // Delete only a particular image size
5153
- if ($size) {
5154
- $abspath = $this->object->get_image_abspath($image, $size);
5155
- if ($abspath && @file_exists($abspath)) {
5156
- @unlink($abspath);
5157
- }
5158
- if (isset($image->meta_data) && isset($image->meta_data[$size])) {
5159
- unset($image->meta_data[$size]);
5160
- $this->object->_image_mapper->save($image);
5161
- }
 
 
 
 
 
5162
  } else {
5163
- foreach ($this->object->get_image_sizes($image) as $named_size) {
5164
- $image_abspath = $this->object->get_image_abspath($image, $named_size);
5165
- @unlink($image_abspath);
5166
  }
5167
- // Delete the entity
5168
- $this->object->_image_mapper->destroy($image);
5169
  }
5170
- $retval = TRUE;
5171
  }
5172
- return $retval;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5173
  }
5174
  /**
5175
- * Recover image from backup copy and reprocess it
5176
  *
5177
- * @param int|stdClass|C_Image $image
5178
- * @return bool|string result code
 
 
5179
  */
5180
- function recover_image($image)
5181
  {
5182
- $retval = FALSE;
5183
- if (is_numeric($image)) {
5184
- $image = $this->object->_image_mapper->find($image);
5185
- }
5186
- if ($image) {
5187
- $full_abspath = $this->object->get_image_abspath($image);
5188
- $backup_abspath = $this->object->get_image_abspath($image, 'backup');
5189
- if ($backup_abspath != $full_abspath && @file_exists($backup_abspath)) {
5190
- if (is_writable($full_abspath) && is_writable(dirname($full_abspath))) {
5191
- // Copy the backup
5192
- if (@copy($backup_abspath, $full_abspath)) {
5193
- // Backup images are not altered at all; we must re-correct the EXIF/Orientation tag
5194
- $this->object->correct_exif_rotation($image, TRUE);
5195
- // Re-create non-fullsize image sizes
5196
- foreach ($this->object->get_image_sizes($image) as $named_size) {
5197
- if (in_array($named_size, array('full', 'backup'))) {
5198
- continue;
5199
- }
5200
- // Reset thumbnail cropping set by 'Edit thumb' dialog
5201
- if ($named_size === 'thumbnail') {
5202
- unset($image->meta_data[$named_size]['crop_frame']);
5203
- }
5204
- $thumbnail = $this->object->generate_image_clone($full_abspath, $this->object->get_image_abspath($image, $named_size), $this->object->get_image_size_params($image, $named_size));
5205
- if ($thumbnail) {
5206
- $thumbnail->destruct();
5207
- }
5208
- }
5209
- do_action('ngg_recovered_image', $image);
5210
- // Reimport all metadata
5211
- $retval = $this->object->_image_mapper->reimport_metadata($image);
5212
- }
5213
- }
5214
- }
5215
  }
5216
- return $retval;
5217
  }
5218
- }
5219
- /**
5220
- * This class contains methods C_Gallery_Storage needs to interact with (like say, importing from) the WP Media Library
5221
- *
5222
- * * @property C_Gallery_Storage $object
5223
- */
5224
- class Mixin_GalleryStorage_Base_MediaLibrary extends Mixin
5225
- {
5226
  /**
5227
- * Copies a NGG image to the media library and returns the attachment_id
5228
  *
5229
- * @param C_Image|int|stdClass $image
5230
- * @return FALSE|int attachment_id
 
 
 
 
5231
  */
5232
- function copy_to_media_library($image)
5233
  {
5234
- $retval = FALSE;
5235
- // Get the image
5236
- if (is_int($image)) {
5237
- $imageId = $image;
5238
- $mapper = C_Image_Mapper::get_instance();
5239
- $image = $mapper->find($imageId);
5240
- }
5241
- if ($image) {
5242
- $subdir = apply_filters('ngg_import_to_media_library_subdir', 'nggallery_import');
5243
- $wordpress_upload_dir = wp_upload_dir();
5244
- $path = $wordpress_upload_dir['path'] . DIRECTORY_SEPARATOR . $subdir;
5245
- if (!file_exists($path)) {
5246
- wp_mkdir_p($path);
5247
- }
5248
- $image_abspath = C_Gallery_Storage::get_instance()->get_image_abspath($image, "full");
5249
- $new_file_path = $path . DIRECTORY_SEPARATOR . $image->filename;
5250
- $image_data = getimagesize($image_abspath);
5251
- $new_file_mime = $image_data['mime'];
5252
- $i = 1;
5253
- while (file_exists($new_file_path)) {
5254
- $i++;
5255
- $new_file_path = $path . DIRECTORY_SEPARATOR . $i . '_' . $image->filename;
 
 
 
 
 
 
 
 
 
 
 
5256
  }
5257
- if (@copy($image_abspath, $new_file_path)) {
5258
- $upload_id = wp_insert_attachment(['guid' => $new_file_path, 'post_mime_type' => $new_file_mime, 'post_title' => preg_replace('/\\.[^.]+$/', '', $image->alttext), 'post_content' => '', 'post_status' => 'inherit'], $new_file_path);
5259
- update_post_meta($upload_id, '_ngg_image_id', intval($image->pid));
5260
- // wp_generate_attachment_metadata() comes from this file
5261
- require_once ABSPATH . 'wp-admin/includes/image.php';
5262
- $image_meta = wp_generate_attachment_metadata($upload_id, $new_file_path);
5263
- // Generate and save the attachment metas into the database
5264
- wp_update_attachment_metadata($upload_id, $image_meta);
5265
- $retval = $upload_id;
5266
  }
5267
  }
5268
- return $retval;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5269
  }
5270
  /**
5271
- * Delete the given NGG image from the media library
5272
- *
5273
- * @var int|stdClass $imageId
5274
  */
5275
- function delete_from_media_library($imageId)
5276
  {
5277
- // Get the image
5278
- if (!is_int($imageId)) {
5279
- $image = $imageId;
5280
- $imageId = $image->pid;
5281
- }
5282
- if ($postId = $this->object->is_in_media_library($imageId)) {
5283
- wp_delete_post($postId);
5284
- }
5285
  }
5286
  /**
5287
- * Determines if the given NGG image id has been uploaded to the media library
5288
- *
5289
- * @param integer $imageId
5290
- * @return FALSE|int attachment_id
 
 
 
 
 
 
 
 
 
 
 
5291
  */
5292
- function is_in_media_library($imageId)
5293
  {
5294
- $retval = FALSE;
5295
- // Get the image
5296
- if (is_object($imageId)) {
5297
- $image = $imageId;
5298
- $imageId = $image->pid;
5299
- }
5300
- // Try to find an attachment for the given image_id
5301
- if ($imageId) {
5302
- $query = new WP_Query(array('post_type' => 'attachment', 'meta_key' => '_ngg_image_id', 'meta_value_num' => $imageId));
5303
- foreach ($query->get_posts() as $post) {
5304
- $retval = $post->ID;
5305
- }
5306
  }
5307
- return $retval;
 
5308
  }
5309
  }
5310
  /**
5311
- * Provides upload-related methods used by C_Gallery_Storage
5312
  * @property C_Gallery_Storage $object
5313
  */
5314
- class Mixin_GalleryStorage_Base_Upload extends Mixin
5315
  {
5316
  /**
5317
- * @param string $abspath
5318
- * @param int $gallery_id
5319
- * @param bool $create_new_gallerypath
5320
- * @param null|string $gallery_title
5321
- * @param array[string] $filenames
5322
- * @return array|bool FALSE on failure
5323
  */
5324
- function import_gallery_from_fs($abspath, $gallery_id = NULL, $create_new_gallerypath = TRUE, $gallery_title = NULL, $filenames = array())
5325
  {
5326
- if (@(!file_exists($abspath))) {
5327
- return FALSE;
 
 
5328
  }
5329
- $fs = C_Fs::get_instance();
5330
- $retval = array('image_ids' => array());
5331
- // Ensure that this folder has images
5332
- $files = array();
5333
- $directories = array();
5334
- foreach (scandir($abspath) as $file) {
5335
- if ($file == '.' || $file == '..' || strtoupper($file) == '__MACOSX') {
5336
- continue;
 
 
 
 
 
5337
  }
5338
- $file_abspath = $fs->join_paths($abspath, $file);
5339
- // Omit 'hidden' directories prefixed with a period
5340
- if (is_dir($file_abspath) && strpos($file, '.') !== 0) {
5341
- $directories[] = $file_abspath;
5342
- } elseif ($this->is_image_file($file_abspath)) {
5343
- if ($filenames && array_search($file_abspath, $filenames) !== FALSE) {
5344
- $files[] = $file_abspath;
 
 
 
 
5345
  } else {
5346
- if (!$filenames) {
5347
- $files[] = $file_abspath;
5348
- }
5349
  }
5350
- }
5351
- }
5352
- if (empty($files) && empty($directories)) {
5353
- return FALSE;
5354
- }
5355
- // Get needed utilities
5356
- $gallery_mapper = C_Gallery_Mapper::get_instance();
5357
- // Recurse through the directory and pull in all of the valid images we find
5358
- if (!empty($directories)) {
5359
- foreach ($directories as $dir) {
5360
- $subImport = $this->object->import_gallery_from_fs($dir, $gallery_id, $create_new_gallerypath, $gallery_title, $filenames);
5361
- if ($subImport) {
5362
- $retval['image_ids'] = array_merge($retval['image_ids'], $subImport['image_ids']);
5363
  }
5364
- }
5365
- }
5366
- // If no gallery has been specified, then use the directory name as the gallery name
5367
- if (!$gallery_id) {
5368
- // Create the gallery
5369
- $gallery = $gallery_mapper->create(array('title' => $gallery_title ? $gallery_title : M_I18n::mb_basename($abspath)));
5370
- if (!$create_new_gallerypath) {
5371
- $gallery_root = $fs->get_document_root('gallery');
5372
- $gallery->path = str_ireplace($gallery_root, '', $abspath);
5373
- }
5374
- // Save the gallery
5375
- if ($gallery->save()) {
5376
- $gallery_id = $gallery->id();
5377
- }
5378
- }
5379
- // Ensure that we have a gallery id
5380
- if (!$gallery_id) {
5381
- return FALSE;
5382
- } else {
5383
- $retval['gallery_id'] = $gallery_id;
5384
- }
5385
- // Remove full sized image if backup is included
5386
- $files_to_import = [];
5387
- foreach ($files as $file_abspath) {
5388
- if (preg_match("#_backup\$#", $file_abspath)) {
5389
- $files_to_import[] = $file_abspath;
5390
- continue;
5391
- } elseif (in_array($file_abspath . "_backup", $files) || strpos("thumbs_", $file_abspath) !== FALSE) {
5392
- continue;
5393
- }
5394
- $files_to_import[] = $file_abspath;
5395
- }
5396
- foreach ($files_to_import as $file_abspath) {
5397
- $basename = preg_replace('#_backup$#', '', pathinfo($file_abspath, PATHINFO_BASENAME));
5398
- if ($this->is_image_file($file_abspath)) {
5399
- if ($image_id = $this->import_image_file($gallery_id, $file_abspath, $basename, FALSE, FALSE, FALSE)) {
5400
- $retval['image_ids'][] = $image_id;
5401
  }
5402
- }
5403
- }
5404
- // Add the gallery name to the result
5405
- if (!isset($gallery)) {
5406
- $gallery = $gallery_mapper->find($gallery_id);
5407
- }
5408
- $retval['gallery_name'] = $gallery->title;
5409
- return $retval;
5410
- }
5411
- /**
5412
- * @param string $filename
5413
- * @return bool
5414
- */
5415
- public function is_allowed_image_extension($filename)
5416
- {
5417
- $extension = pathinfo($filename, PATHINFO_EXTENSION);
5418
- $extension = strtolower($extension);
5419
- $allowed_extensions = apply_filters('ngg_allowed_file_types', array('jpeg', 'jpg', 'png', 'gif'));
5420
- foreach ($allowed_extensions as $extension) {
5421
- $allowed_extensions[] = $extension . '_backup';
5422
- }
5423
- return in_array($extension, $allowed_extensions);
5424
- }
5425
- function is_current_user_over_quota()
5426
- {
5427
- $retval = FALSE;
5428
- $settings = C_NextGen_Settings::get_instance();
5429
- if (is_multisite() && $settings->get('wpmuQuotaCheck')) {
5430
- require_once ABSPATH . 'wp-admin/includes/ms.php';
5431
- $retval = upload_is_user_over_quota(FALSE);
5432
  }
5433
  return $retval;
5434
  }
5435
  /**
5436
- * @param string? $filename
 
5437
  * @return bool
5438
  */
5439
- function is_image_file($filename = NULL)
5440
  {
5441
- $retval = FALSE;
5442
- if (!$filename && isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
5443
- $filename = $_FILES['file']['tmp_name'];
5444
- }
5445
- $valid_types = array('image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png');
5446
- // If we can, we'll verify the mime type
5447
- if (function_exists('exif_imagetype')) {
5448
- if (($image_type = @exif_imagetype($filename)) !== FALSE) {
5449
- $retval = in_array(image_type_to_mime_type($image_type), $valid_types);
5450
- }
5451
- } else {
5452
- $file_info = @getimagesize($filename);
5453
- if (isset($file_info[2])) {
5454
- $retval = in_array(image_type_to_mime_type($file_info[2]), $valid_types);
5455
- }
5456
  }
5457
  return $retval;
5458
  }
5459
- function is_zip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5460
  {
5461
- $retval = FALSE;
5462
- if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
5463
- $file_info = $_FILES['file'];
5464
- if (isset($file_info['type'])) {
5465
- $type = $file_info['type'];
5466
- $type_parts = explode('/', $type);
5467
- if (strtolower($type_parts[0]) == 'application') {
5468
- $spec = $type_parts[1];
5469
- $spec_parts = explode('-', $spec);
5470
- $spec_parts = array_map('strtolower', $spec_parts);
5471
- if (in_array($spec, array('zip', 'octet-stream')) || in_array('zip', $spec_parts)) {
5472
- $retval = true;
5473
- }
5474
- }
5475
- }
5476
  }
5477
  return $retval;
5478
  }
5479
- function maybe_base64_decode($data)
5480
  {
5481
- $decoded = base64_decode($data);
5482
- if ($decoded === FALSE) {
5483
- return $data;
5484
- } else {
5485
- if (base64_encode($decoded) == $data) {
5486
- return base64_decode($data);
5487
- }
5488
- }
5489
- return $data;
5490
  }
5491
- function get_unique_abspath($file_abspath)
5492
  {
5493
- $filename = basename($file_abspath);
5494
- $dir_abspath = dirname($file_abspath);
5495
- $num = 1;
5496
- $pattern = path_join($dir_abspath, "*_{$filename}");
5497
- if ($found = glob($pattern)) {
5498
- natsort($found);
5499
- $last = array_pop($found);
5500
- $last = basename($last);
5501
- if (preg_match("/^(\\d+)_/", $last, $match)) {
5502
- $num = intval($match[1]) + 1;
5503
- }
5504
- }
5505
- return path_join($dir_abspath, "{$num}_{$filename}");
5506
  }
5507
- function sanitize_filename_for_db($filename = NULL)
 
 
 
 
 
 
 
5508
  {
5509
- $filename = $filename ? $filename : uniqid('nextgen-gallery');
5510
- $filename = preg_replace("#^/#", "", $filename);
5511
- $filename = sanitize_file_name($filename);
5512
- if (preg_match("/\\-(png|jpg|gif|jpeg|jpg_backup)\$/i", $filename, $match)) {
5513
- $filename = str_replace($match[0], '.' . $match[1], $filename);
 
5514
  }
5515
- return $filename;
 
5516
  }
5517
- function import_image_file($dst_gallery, $image_abspath, $filename = NULL, $image = FALSE, $override = FALSE, $move = FALSE)
 
 
 
 
 
 
5518
  {
5519
- $image_abspath = wp_normalize_path($image_abspath);
5520
- if ($this->object->is_current_user_over_quota()) {
5521
- $message = sprintf(__('Sorry, you have used your space allocation. Please delete some files to upload more files.', 'nggallery'));
5522
- throw new E_NoSpaceAvailableException($message);
5523
- }
5524
- // Do we have a gallery to import to?
5525
- if ($dst_gallery) {
5526
- // Get the gallery abspath. This is where we will put the image files
5527
- $gallery_abspath = $this->object->get_gallery_abspath($dst_gallery);
5528
- // If we can't write to the directory, then there's no point in continuing
5529
- if (!@file_exists($gallery_abspath)) {
5530
- @wp_mkdir_p($gallery_abspath);
5531
- }
5532
- if (!is_writable($gallery_abspath)) {
5533
- throw new E_InsufficientWriteAccessException(FALSE, $gallery_abspath, FALSE);
5534
- }
5535
- // Sanitize the filename for storing in the DB
5536
- $filename = $this->sanitize_filename_for_db($filename);
5537
- // Ensure that the filename is valid
5538
- if (!preg_match("/(png|jpeg|jpg|gif|_backup)\$/i", $filename)) {
5539
- throw new E_UploadException(__('Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery'));
5540
- }
5541
- // Compute the destination folder
5542
- $new_image_abspath = path_join($gallery_abspath, $filename);
5543
- // Are the src and dst the same? If so, we don't have to copy or move files
5544
- if ($image_abspath != $new_image_abspath) {
5545
- // If we're not to override, ensure that the filename is unique
5546
- if (!$override && @file_exists($new_image_abspath)) {
5547
- $new_image_abspath = $this->object->get_unique_abspath($new_image_abspath);
5548
- $filename = $this->sanitize_filename_for_db(basename($new_image_abspath));
5549
- }
5550
- // Try storing the file
5551
- $copied = copy($image_abspath, $new_image_abspath);
5552
- if ($copied && $move) {
5553
- unlink($image_abspath);
5554
- }
5555
- // Ensure that we're not vulerable to CVE-2017-2416 exploit
5556
- if (($dimensions = getimagesize($new_image_abspath)) !== FALSE) {
5557
- if (isset($dimensions[0]) && intval($dimensions[0]) > 30000 || isset($dimensions[1]) && intval($dimensions[1]) > 30000) {
5558
- unlink($new_image_abspath);
5559
- throw new E_UploadException(__('Image file too large. Maximum image dimensions supported are 30k x 30k.'));
5560
- }
5561
- }
5562
- }
5563
- // Save the image in the DB
5564
- $image_mapper = C_Image_Mapper::get_instance();
5565
- $image_mapper->_use_cache = FALSE;
5566
- if ($image) {
5567
- if (is_numeric($image)) {
5568
- $image = $image_mapper->find($image);
5569
- }
5570
- }
5571
- if (!$image) {
5572
- $image = $image_mapper->create();
5573
- }
5574
- $image->alttext = preg_replace("#\\.\\w{2,4}\$#", "", $filename);
5575
- $image->galleryid = is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid;
5576
- $image->filename = $filename;
5577
- $image->image_slug = nggdb::get_unique_slug(sanitize_title_with_dashes($image->alttext), 'image');
5578
- $image_id = $image_mapper->save($image);
5579
- if (!$image_id) {
5580
- $exception = '';
5581
- foreach ($image->get_errors() as $field => $errors) {
5582
- foreach ($errors as $error) {
5583
- if (!empty($exception)) {
5584
- $exception .= "<br/>";
5585
- }
5586
- $exception .= __(sprintf("Error while uploading %s: %s", $filename, $error), 'nextgen-gallery');
5587
- }
5588
- }
5589
- throw new E_UploadException($exception);
5590
- }
5591
- // Important: do not remove this line. The image mapper's save() routine imports metadata
5592
- // meaning we must re-acquire a new $image object after saving it above; if we do not our
5593
- // existing $image object will lose any metadata retrieved during said save() method.
5594
- $image = $image_mapper->find($image_id);
5595
- $image_mapper->_use_cache = TRUE;
5596
- $settings = C_NextGen_Settings::get_instance();
5597
- // Backup the image
5598
- if ($settings->get('imgBackup', FALSE)) {
5599
- $this->object->backup_image($image, TRUE);
5600
- }
5601
- // Most browsers do not honor EXIF's Orientation header: rotate the image to prevent display issues
5602
- $this->object->correct_exif_rotation($image, TRUE);
5603
- // Create resized version of image
5604
- if ($settings->get('imgAutoResize', FALSE)) {
5605
- $this->object->generate_resized_image($image, TRUE);
5606
- }
5607
- // Generate a thumbnail for the image
5608
- $this->object->generate_thumbnail($image);
5609
- // Set gallery preview image if missing
5610
- C_Gallery_Mapper::get_instance()->set_preview_image($dst_gallery, $image_id, TRUE);
5611
- // Automatically watermark the main image if requested
5612
- if ($settings->get('watermark_automatically_at_upload', 0)) {
5613
- $image_abspath = $this->object->get_image_abspath($image, 'full');
5614
- $this->object->generate_image_clone($image_abspath, $image_abspath, array('watermark' => TRUE));
5615
  }
5616
- // Notify other plugins that an image has been added
5617
- do_action('ngg_added_new_image', $image);
5618
- // delete dirsize after adding new images
5619
- delete_transient('dirsize_cache');
5620
- // Seems redundant to above hook. Maintaining for legacy purposes
5621
- do_action('ngg_after_new_images_added', is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid, array($image_id));
5622
- return $image_id;
5623
  } else {
5624
- throw new E_EntityNotFoundException();
 
 
 
 
5625
  }
5626
- return NULL;
 
 
 
 
 
 
 
 
 
 
5627
  }
5628
  /**
5629
- * Uploads base64 file to a gallery
5630
- * @param int|stdClass|C_Gallery $gallery
5631
- * @param $data base64-encoded string of data representing the image
5632
- * @param string|false (optional) $filename specifies the name of the file
5633
- * @param int|false $image_id (optional)
5634
- * @param bool $override (optional)
5635
- * @return C_Image
5636
  */
5637
- function upload_base64_image($gallery, $data, $filename = FALSE, $image_id = FALSE, $override = FALSE, $move = FALSE)
5638
  {
5639
- try {
5640
- $temp_abspath = tempnam(sys_get_temp_dir(), '');
5641
- // Try writing the image
5642
- $fp = fopen($temp_abspath, 'wb');
5643
- fwrite($fp, $this->maybe_base64_decode($data));
5644
- fclose($fp);
5645
- } catch (E_UploadException $ex) {
5646
- throw $ex;
5647
- }
5648
- return $this->object->import_image_file($gallery, $temp_abspath, $filename, $image_id, $override, $move);
5649
  }
 
 
 
 
 
 
 
5650
  /**
5651
- * Uploads an image for a particular gallery
5652
- * @param int|object|C_Gallery $gallery
5653
- * @param string|bool $filename (optional) Specifies the name of the file
5654
- * @param string|bool $data (optional) If specified, expects base64 encoded string of data
5655
- * @return C_Image
5656
  */
5657
- function upload_image($gallery, $filename = FALSE, $data = FALSE)
5658
  {
5659
- $retval = NULL;
5660
- // Ensure that we have the data present that we require
5661
- if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
5662
- // $_FILES = Array(
5663
- // [file] => Array (
5664
- // [name] => Canada_landscape4.jpg
5665
- // [type] => image/jpeg
5666
- // [tmp_name] => /private/var/tmp/php6KO7Dc
5667
- // [error] => 0
5668
- // [size] => 64975
5669
- // )
5670
- //
5671
- $file = $_FILES['file'];
5672
- if ($this->object->is_zip()) {
5673
- $retval = $this->object->upload_zip($gallery);
5674
- } else {
5675
- if ($this->is_image_file()) {
5676
- $retval = $this->object->import_image_file($gallery, $file['tmp_name'], $filename ? $filename : (isset($file['name']) ? $file['name'] : FALSE), FALSE, FALSE, TRUE);
5677
- } else {
5678
- // Remove the non-valid (and potentially insecure) file from the PHP upload directory
5679
- if (isset($_FILES['file']['tmp_name'])) {
5680
- $filename = $_FILES['file']['tmp_name'];
5681
- @unlink($filename);
5682
  }
5683
- throw new E_UploadException(__('Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery'));
5684
  }
5685
  }
5686
- } elseif ($data) {
5687
- $retval = $this->object->upload_base64_image($gallery, $data, $filename);
5688
- } else {
5689
- throw new E_UploadException();
5690
  }
5691
  return $retval;
5692
  }
 
 
 
 
 
 
 
5693
  /**
 
5694
  * @param int $gallery_id
5695
- * @return array|bool
 
 
 
5696
  */
5697
- function upload_zip($gallery_id)
5698
  {
5699
- if (!$this->object->is_zip()) {
5700
  return FALSE;
5701
  }
5702
- $retval = FALSE;
5703
- $memory_limit = intval(ini_get('memory_limit'));
5704
- if (!extension_loaded('suhosin') && $memory_limit < 256) {
5705
- @ini_set('memory_limit', '256M');
5706
- }
5707
  $fs = C_Fs::get_instance();
5708
- // Uses the WordPress ZIP abstraction API
5709
- include_once $fs->join_paths(ABSPATH, 'wp-admin', 'includes', 'file.php');
5710
- WP_Filesystem(FALSE, get_temp_dir(), TRUE);
5711
- // Ensure that we truly have the gallery id
5712
- $gallery_id = $this->object->_get_gallery_id($gallery_id);
5713
- $zipfile = $_FILES['file']['tmp_name'];
5714
- $dest_path = implode(DIRECTORY_SEPARATOR, array(rtrim(get_temp_dir(), "/\\"), 'unpacked-' . M_I18n::mb_basename($zipfile)));
5715
- // Attempt to extract the zip file into the normal system directory
5716
- $extracted = $this->object->extract_zip($zipfile, $dest_path);
5717
- // Now verify it worked. get_temp_dir() will check each of the following directories to ensure they are
5718
- // a directory and against wp_is_writable(). Should ALL of those options fail we will fallback to wp_upload_dir().
5719
- //
5720
- // WP_TEMP_DIR
5721
- // sys_get_temp_dir()
5722
- // ini/upload_tmp_dir
5723
- // WP_CONTENT_DIR
5724
- // /tmp
5725
- $size = 0;
5726
- $files = glob($dest_path . DIRECTORY_SEPARATOR . '*');
5727
- foreach ($files as $file) {
5728
- if (is_array(stat($file))) {
5729
- $size += filesize($file);
5730
  }
5731
  }
5732
- // Extraction failed; attempt again with wp_upload_dir()
5733
- if ($size == 0) {
5734
- // Remove the empty directory we may have possibly created but could not write to
5735
- $this->object->delete_directory($dest_path);
5736
- $destination = wp_upload_dir();
5737
- $destination_path = $destination['basedir'];
5738
- $dest_path = implode(DIRECTORY_SEPARATOR, array(rtrim($destination_path, "/\\"), rand(), 'unpacked-' . M_I18n::mb_basename($zipfile)));
5739
- $extracted = $this->object->extract_zip($zipfile, $dest_path);
5740
- }
5741
- if ($extracted) {
5742
- $retval = $this->object->import_gallery_from_fs($dest_path, $gallery_id);
5743
  }
5744
- $this->object->delete_directory($dest_path);
5745
- if (!extension_loaded('suhosin')) {
5746
- @ini_set('memory_limit', $memory_limit . 'M');
 
 
 
 
 
 
 
5747
  }
5748
- return $retval;
5749
- }
5750
- /**
5751
- * @param string $zipfile
5752
- * @param string $dest_path
5753
- * @return bool FALSE on failure
5754
- */
5755
- public function extract_zip($zipfile, $dest_path)
5756
- {
5757
- wp_mkdir_p($dest_path);
5758
- if (class_exists('ZipArchive', FALSE) && apply_filters('unzip_file_use_ziparchive', TRUE)) {
5759
- $zipObj = new ZipArchive();
5760
- if ($zipObj->open($zipfile) === FALSE) {
5761
- return FALSE;
5762
  }
5763
- for ($i = 0; $i < $zipObj->numFiles; $i++) {
5764
- $filename = $zipObj->getNameIndex($i);
5765
- if (!$this->object->is_allowed_image_extension($filename)) {
5766
- continue;
5767
- }
5768
- $zipObj->extractTo($dest_path, array($zipObj->getNameIndex($i)));
5769
  }
 
 
 
 
5770
  } else {
5771
- require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
5772
- $zipObj = new PclZip($zipfile);
5773
- $zipContent = $zipObj->listContent();
5774
- $indexesToExtract = array();
5775
- foreach ($zipContent as $zipItem) {
5776
- if ($zipItem['folder']) {
5777
- continue;
5778
- }
5779
- if (!$this->object->is_allowed_image_extension($zipItem['stored_filename'])) {
5780
- continue;
5781
- }
5782
- $indexesToExtract[] = $zipItem['index'];
5783
  }
5784
- if (!$zipObj->extractByIndex(implode(',', $indexesToExtract), $dest_path)) {
5785
- return FALSE;
 
 
 
 
 
 
5786
  }
5787
  }
5788
- return TRUE;
 
 
 
 
 
5789
  }
5790
  }
5791
  /**
188
  }
189
  return self::$_instance;
190
  }
191
+ /**
192
+ * @param string $slug
193
+ * @return null|stdClass|C_Album
194
+ */
195
+ public function get_by_slug($slug)
196
+ {
197
+ return array_pop($this->object->select()->where(['slug = %s', sanitize_title($slug)])->limit(1)->run_query());
198
+ }
199
  }
200
  /**
201
  * Provides album-specific methods for the datamapper
220
  }
221
  return $retval;
222
  }
 
 
 
 
 
 
 
 
223
  /**
224
  * Sets the defaults for an album
225
  * @param C_DataMapper_Model|C_Album|stdClass $entity
234
  if (isset($entity->name) && !isset($entity->slug)) {
235
  $entity->slug = nggdb::get_unique_slug(sanitize_title($entity->name), 'album');
236
  }
237
+ if (!is_admin()) {
238
+ if (!empty($entity->name)) {
239
+ $entity->name = M_I18N::translate($entity->name, 'album_' . $entity->{$entity->id_field} . '_name');
240
+ }
241
+ if (!empty($entity->albumdesc)) {
242
+ $entity->albumdesc = M_I18N::translate($entity->albumdesc, 'album_' . $entity->{$entity->id_field} . '_description');
243
+ }
244
+ // these fields are set when the album is a child to another album
245
+ if (!empty($entity->title)) {
246
+ $entity->title = M_I18N::translate($entity->title, 'album_' . $entity->{$entity->id_field} . '_name');
247
+ }
248
+ if (!empty($entity->galdesc)) {
249
+ $entity->galdesc = M_I18N::translate($entity->galdesc, 'album_' . $entity->{$entity->id_field} . '_description');
250
+ }
251
+ }
252
  }
253
  }
254
  class Mixin_Dynamic_Thumbnails_Manager extends Mixin
811
  return in_array(strtolower($extension), array('jpeg', 'jpg', 'jpeg_backup', 'jpg_backup')) ? TRUE : FALSE;
812
  }
813
  }
814
+ /**
815
+ * Creates a model representing a NextGEN Gallery object
816
+ * @mixin Mixin_NextGen_Gallery_Validation
817
+ * @implements I_Gallery
818
+ */
819
+ class C_Gallery extends C_DataMapper_Model
820
+ {
821
+ var $_mapper_interface = 'I_Gallery_Mapper';
822
+ /**
823
+ * Defines the interfaces and methods (through extensions and hooks)
824
+ * that this class provides
825
+ */
826
+ function define($properties = array(), $mapper = FALSE, $context = FALSE)
827
+ {
828
+ parent::define($mapper, $properties, $context);
829
+ $this->add_mixin('Mixin_NextGen_Gallery_Validation');
830
+ $this->implement('I_Gallery');
831
+ }
832
+ /**
833
+ * Instantiates a new model
834
+ * @param array|stdClass $properties (optional)
835
+ * @param C_Gallery_Mapper|false $mapper (optional)
836
+ * @param string|bool $context (optional)
837
+ */
838
+ function initialize($properties = array(), $mapper = FALSE, $context = FALSE)
839
+ {
840
+ if (!$mapper) {
841
+ $mapper = $this->get_registry()->get_utility($this->_mapper_interface);
842
+ }
843
+ parent::initialize($mapper, $properties);
844
+ }
845
+ function get_images()
846
+ {
847
+ $mapper = C_Image_Mapper::get_instance();
848
+ return $mapper->select()->where(array('galleryid = %d', $this->gid))->order_by('sortorder')->run_query();
849
+ }
850
+ }
851
  class Mixin_NextGen_Gallery_Validation
852
  {
853
  /**
931
  return $this->object->is_valid();
932
  }
933
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
934
  /**
935
  * Provides a datamapper for galleries
936
  * @mixin Mixin_NextGen_Table_Extras
987
  }
988
  return self::$_instance;
989
  }
 
 
 
 
 
 
 
 
 
 
 
 
990
  /**
991
  * @param string $slug
992
  * @return C_Gallery|stdClass|null
1002
  }
1003
  return reset($retval);
1004
  }
1005
+ function set_preview_image($gallery, $image, $only_if_empty = FALSE)
1006
+ {
1007
+ $retval = FALSE;
1008
+ // We need the gallery object
1009
+ if (is_numeric($gallery)) {
1010
+ $gallery = $this->object->find($gallery);
1011
+ }
1012
+ // We need the image id
1013
+ if (!is_numeric($image)) {
1014
+ if (method_exists($image, 'id')) {
1015
+ $image = $image->id();
1016
+ } else {
1017
+ $image = $image->{$image->id_field};
1018
+ }
1019
+ }
1020
+ if ($gallery && $image) {
1021
+ if ($only_if_empty && !$gallery->previewpic or !$only_if_empty) {
1022
+ $gallery->previewpic = $image;
1023
+ $retval = $this->object->save($gallery);
1024
+ }
1025
+ }
1026
+ return $retval;
1027
+ }
1028
+ }
1029
+ class Mixin_Gallery_Mapper extends Mixin
1030
+ {
1031
+ /**
1032
+ * Uses the title property as the post title when the Custom Post driver is used
1033
+ * @param object $entity
1034
+ * @return string
1035
+ */
1036
+ function get_post_title($entity)
1037
+ {
1038
+ return $entity->title;
1039
+ }
1040
  function _save_entity($entity)
1041
  {
1042
  $storage = C_Gallery_Storage::get_instance();
1116
  }
1117
  return $retval;
1118
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1119
  /**
1120
  * Sets default values for the gallery
1121
  * @param object $entity
1125
  // If author is missing, then set to the current user id
1126
  // TODO: Using wordpress function. Should use abstraction
1127
  $this->object->_set_default_value($entity, 'author', get_current_user_id());
1128
+ if (!is_admin()) {
1129
+ if (!empty($entity->title)) {
1130
+ $entity->title = M_I18N::translate($entity->title, 'gallery_' . $entity->{$entity->id_field} . '_name');
1131
+ }
1132
+ if (!empty($entity->galdesc)) {
1133
+ $entity->galdesc = M_I18N::translate($entity->galdesc, 'gallery_' . $entity->{$entity->id_field} . '_description');
1134
+ }
1135
+ }
1136
  }
1137
  }
1138
  class E_UploadException extends E_NggErrorException
1196
  }
1197
  /**
1198
  * Class C_Gallery_Storage
1199
+ *
1200
  * @implements I_Gallery_Storage
 
1201
  * @mixin Mixin_GalleryStorage_Base_Dynamic
1202
  * @mixin Mixin_GalleryStorage_Base_Getters
1203
  * @mixin Mixin_GalleryStorage_Base_Management
 
1204
  * @mixin Mixin_GalleryStorage_Base_Upload
1205
  */
1206
  class C_Gallery_Storage extends C_Component
1207
  {
1208
  public static $_instances = array();
1209
+ static $gallery_abspath_cache = array();
1210
  function define($context = FALSE)
1211
  {
1212
  parent::define($context);
 
1213
  $this->add_mixin('Mixin_GalleryStorage_Base_Dynamic');
1214
  $this->add_mixin('Mixin_GalleryStorage_Base_Getters');
1215
  $this->add_mixin('Mixin_GalleryStorage_Base_Management');
 
1216
  $this->add_mixin('Mixin_GalleryStorage_Base_Upload');
1217
  $this->implement('I_Gallery_Storage');
1218
  $this->implement('I_GalleryStorage_Driver');
1263
  }
1264
  return self::$_instances[$context];
1265
  }
1266
+ /**
1267
+ * Gets the id of a gallery, regardless of whether an integer
1268
+ * or object was passed as an argument
1269
+ * @param mixed $gallery_obj_or_id
1270
+ * @return null|int
1271
+ */
1272
+ function _get_gallery_id($gallery_obj_or_id)
1273
  {
1274
+ $retval = NULL;
1275
+ $gallery_key = $this->object->_gallery_mapper->get_primary_key_column();
1276
+ if (is_object($gallery_obj_or_id)) {
1277
+ if (isset($gallery_obj_or_id->{$gallery_key})) {
1278
+ $retval = $gallery_obj_or_id->{$gallery_key};
1279
+ }
1280
+ } elseif (is_numeric($gallery_obj_or_id)) {
1281
+ $retval = $gallery_obj_or_id;
1282
  }
1283
+ return $retval;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1284
  }
1285
  /**
1286
+ * Outputs/renders an image
1287
+ * @param int|stdClass|C_Image $image
1288
+ * @return bool
 
1289
  */
1290
+ function render_image($image, $size = FALSE)
1291
  {
1292
+ $format_list = $this->object->get_image_format_list();
1293
+ $abspath = $this->object->get_image_abspath($image, $size, true);
1294
+ if ($abspath == null) {
1295
+ $thumbnail = $this->object->generate_image_size($image, $size);
1296
+ if ($thumbnail != null) {
1297
+ $abspath = $thumbnail->fileName;
1298
+ $thumbnail->destruct();
1299
+ }
1300
  }
1301
+ if ($abspath != null) {
1302
+ $data = @getimagesize($abspath);
1303
+ $format = 'jpg';
1304
+ if ($data != null && is_array($data) && isset($format_list[$data[2]])) {
1305
+ $format = $format_list[$data[2]];
1306
+ }
1307
+ // Clear output
1308
+ while (ob_get_level() > 0) {
1309
+ ob_end_clean();
1310
+ }
1311
+ $format = strtolower($format);
1312
+ // output image and headers
1313
+ header('Content-type: image/' . $format);
1314
+ readfile($abspath);
1315
+ return true;
1316
+ }
1317
+ return false;
1318
  }
1319
  /**
1320
+ * Sets a NGG image as a post thumbnail for the given post
1321
+ *
1322
+ * @param int $postId
1323
+ * @param int|C_Image|stdClass $image
1324
+ * @param bool $only_create_attachment
1325
+ * @return int
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1326
  */
1327
+ function set_post_thumbnail($postId, $image, $only_create_attachment = FALSE)
1328
  {
1329
+ $retval = FALSE;
1330
+ // Get the post ID
1331
+ if (is_object($postId)) {
1332
+ $post = $postId;
1333
+ $postId = isset($post->ID) ? $post->ID : $post->post_id;
1334
  }
1335
+ // Get the image
1336
+ if (is_int($image)) {
1337
+ $imageId = $image;
1338
+ $mapper = C_Image_Mapper::get_instance();
1339
+ $image = $mapper->find($imageId);
 
 
 
 
 
 
 
 
 
1340
  }
1341
+ if ($image && $postId) {
1342
+ $attachment_id = $this->object->is_in_media_library($image->pid);
1343
+ if ($attachment_id === FALSE) {
1344
+ $attachment_id = $this->object->copy_to_media_library($image);
1345
+ }
1346
+ if ($attachment_id) {
1347
+ if (!$only_create_attachment) {
1348
+ set_post_thumbnail($postId, $attachment_id);
1349
+ }
1350
+ $retval = $attachment_id;
 
 
 
 
1351
  }
 
1352
  }
1353
  return $retval;
1354
  }
1355
+ function convert_slashes($path)
1356
  {
1357
+ $search = array('/', "\\");
1358
+ $replace = array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR);
1359
+ return str_replace($search, $replace, $path);
 
 
 
 
 
 
 
 
 
 
1360
  }
1361
  /**
1362
+ * Empties the gallery cache directory of content
1363
+ * @param object $gallery
 
1364
  */
1365
+ function flush_cache($gallery)
1366
  {
1367
+ $cache = C_Cache::get_instance();
1368
+ $cache->flush_directory($this->object->get_cache_abspath($gallery));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1369
  }
1370
+ /**
1371
+ * Sanitizes a directory path, replacing whitespace with dashes.
1372
+ *
1373
+ * Taken from WP' sanitize_file_name() and modified to not act on file extensions.
1374
+ *
1375
+ * Removes special characters that are illegal in filenames on certain
1376
+ * operating systems and special characters requiring special escaping
1377
+ * to manipulate at the command line. Replaces spaces and consecutive
1378
+ * dashes with a single dash. Trims period, dash and underscore from beginning
1379
+ * and end of filename. It is not guaranteed that this function will return a
1380
+ * filename that is allowed to be uploaded.
1381
+ * @param string $dirname The directory name to be sanitized
1382
+ * @return string The sanitized directory name
1383
+ */
1384
+ public function sanitize_directory_name($dirname)
1385
  {
1386
+ $dirname_raw = $dirname;
1387
+ $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "\$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0));
1388
+ $special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $dirname_raw);
1389
+ $dirname = preg_replace("#\\x{00a0}#siu", ' ', $dirname);
1390
+ $dirname = str_replace($special_chars, '', $dirname);
1391
+ $dirname = str_replace(array('%20', '+'), '-', $dirname);
1392
+ $dirname = preg_replace('/[\\r\\n\\t -]+/', '-', $dirname);
1393
+ $dirname = trim($dirname, '.-_');
1394
+ return $dirname;
1395
  }
1396
+ /**
1397
+ * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated
1398
+ * @param object|int $image Image ID or an image object
1399
+ * @param string $size
1400
+ * @param array $params
1401
+ * @param bool $skip_defaults
1402
+ * @return bool|array
1403
+ */
1404
+ function calculate_image_size_dimensions($image, $size, $params = null, $skip_defaults = false)
1405
  {
1406
+ $retval = FALSE;
1407
+ // Get the image entity
1408
+ if (is_numeric($image)) {
1409
+ $image = $this->object->_image_mapper->find($image);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1410
  }
1411
+ // Ensure we have a valid image
1412
+ if ($image) {
1413
+ $params = $this->object->get_image_size_params($image, $size, $params, $skip_defaults);
1414
+ // Get the image filename
1415
+ $image_path = $this->object->get_original_abspath($image, 'original');
1416
+ $clone_path = $this->object->get_image_abspath($image, $size);
1417
+ $retval = $this->object->calculate_image_clone_dimensions($image_path, $clone_path, $params);
1418
  }
1419
+ return $retval;
 
 
1420
  }
1421
  /**
1422
+ * Generates a "clone" for an existing image, the clone can be altered using the $params array
1423
+ * @param string $image_path
1424
+ * @param string $clone_path
1425
+ * @param array $params
1426
+ * @return null|object
1427
  */
1428
+ function generate_image_clone($image_path, $clone_path, $params)
1429
  {
1430
+ $crop = isset($params['crop']) ? $params['crop'] : NULL;
1431
+ $watermark = isset($params['watermark']) ? $params['watermark'] : NULL;
1432
+ $reflection = isset($params['reflection']) ? $params['reflection'] : NULL;
1433
+ $rotation = isset($params['rotation']) ? $params['rotation'] : NULL;
1434
+ $flip = isset($params['flip']) ? $params['flip'] : NULL;
1435
+ $destpath = NULL;
1436
+ $thumbnail = NULL;
1437
+ $result = $this->object->calculate_image_clone_result($image_path, $clone_path, $params);
1438
+ // XXX this should maybe be removed and extra settings go into $params?
1439
+ $settings = apply_filters('ngg_settings_during_image_generation', C_NextGen_Settings::get_instance()->to_array());
1440
+ // Ensure we have a valid image
1441
+ if ($image_path && @file_exists($image_path) && $result != null && !isset($result['error'])) {
1442
+ $image_dir = dirname($image_path);
1443
+ $clone_path = $result['clone_path'];
1444
+ $clone_dir = $result['clone_directory'];
1445
+ $clone_format = $result['clone_format'];
1446
+ $format_list = $this->object->get_image_format_list();
1447
+ // Ensure target directory exists, but only create 1 subdirectory
1448
+ if (!@file_exists($clone_dir)) {
1449
+ if (strtolower(realpath($image_dir)) != strtolower(realpath($clone_dir))) {
1450
+ if (strtolower(realpath($image_dir)) == strtolower(realpath(dirname($clone_dir)))) {
1451
+ wp_mkdir_p($clone_dir);
1452
+ }
1453
  }
1454
  }
1455
+ $method = $result['method'];
1456
+ $width = $result['width'];
1457
+ $height = $result['height'];
1458
+ $quality = $result['quality'];
1459
+ if ($quality == null) {
1460
+ $quality = 100;
1461
+ }
1462
+ if ($method == 'wordpress') {
1463
+ $original = wp_get_image_editor($image_path);
1464
+ $destpath = $clone_path;
1465
+ if (!is_wp_error($original)) {
1466
+ $original->resize($width, $height, $crop);
1467
+ $original->set_quality($quality);
1468
+ $original->save($clone_path);
1469
+ }
1470
+ } else {
1471
+ if ($method == 'nextgen') {
1472
+ $destpath = $clone_path;
1473
+ $thumbnail = new C_NggLegacy_Thumbnail($image_path, true);
1474
+ if (!$thumbnail->error) {
1475
+ if ($crop) {
1476
+ $crop_area = $result['crop_area'];
1477
+ $crop_x = $crop_area['x'];
1478
+ $crop_y = $crop_area['y'];
1479
+ $crop_width = $crop_area['width'];
1480
+ $crop_height = $crop_area['height'];
1481
+ $thumbnail->crop($crop_x, $crop_y, $crop_width, $crop_height);
1482
+ }
1483
+ $thumbnail->resize($width, $height);
1484
+ } else {
1485
+ $thumbnail = NULL;
1486
+ }
1487
+ }
1488
+ }
1489
+ // We successfully generated the thumbnail
1490
+ if (is_string($destpath) && (@file_exists($destpath) || $thumbnail != null)) {
1491
+ if ($clone_format != null) {
1492
+ if (isset($format_list[$clone_format])) {
1493
+ $clone_format_extension = $format_list[$clone_format];
1494
+ $clone_format_extension_str = null;
1495
+ if ($clone_format_extension != null) {
1496
+ $clone_format_extension_str = '.' . $clone_format_extension;
1497
+ }
1498
+ $destpath_info = M_I18n::mb_pathinfo($destpath);
1499
+ $destpath_extension = $destpath_info['extension'];
1500
+ if (strtolower($destpath_extension) != strtolower($clone_format_extension)) {
1501
+ $destpath_dir = $destpath_info['dirname'];
1502
+ $destpath_basename = $destpath_info['filename'];
1503
+ $destpath_new = $destpath_dir . DIRECTORY_SEPARATOR . $destpath_basename . $clone_format_extension_str;
1504
+ if (@file_exists($destpath) && rename($destpath, $destpath_new) || $thumbnail != null) {
1505
+ $destpath = $destpath_new;
1506
+ }
1507
+ }
1508
+ }
1509
+ }
1510
+ if (is_null($thumbnail)) {
1511
+ $thumbnail = new C_NggLegacy_Thumbnail($destpath, true);
1512
+ if ($thumbnail->error) {
1513
+ $thumbnail = null;
1514
+ return null;
1515
+ }
1516
+ } else {
1517
+ $thumbnail->fileName = $destpath;
1518
+ }
1519
+ // This is quite odd, when watermark equals int(0) it seems all statements below ($watermark == 'image') and ($watermark == 'text') both evaluate as true
1520
+ // so we set it at null if it evaluates to any null-like value
1521
+ if ($watermark == null) {
1522
+ $watermark = null;
1523
+ }
1524
+ if ($watermark == 1 || $watermark === true) {
1525
+ $watermark_setting_keys = array('wmFont', 'wmType', 'wmPos', 'wmXpos', 'wmYpos', 'wmPath', 'wmText', 'wmOpaque', 'wmFont', 'wmSize', 'wmColor');
1526
+ foreach ($watermark_setting_keys as $watermark_key) {
1527
+ if (!isset($params[$watermark_key])) {
1528
+ $params[$watermark_key] = $settings[$watermark_key];
1529
+ }
1530
+ }
1531
+ if (in_array(strval($params['wmType']), array('image', 'text'))) {
1532
+ $watermark = $params['wmType'];
1533
+ } else {
1534
+ $watermark = 'text';
1535
+ }
1536
+ }
1537
+ $watermark = strval($watermark);
1538
+ if ($watermark == 'image') {
1539
+ $thumbnail->watermarkImgPath = $params['wmPath'];
1540
+ $thumbnail->watermarkImage($params['wmPos'], $params['wmXpos'], $params['wmYpos']);
1541
+ } else {
1542
+ if ($watermark == 'text') {
1543
+ $thumbnail->watermarkText = $params['wmText'];
1544
+ $thumbnail->watermarkCreateText($params['wmColor'], $params['wmFont'], $params['wmSize'], $params['wmOpaque']);
1545
+ $thumbnail->watermarkImage($params['wmPos'], $params['wmXpos'], $params['wmYpos']);
1546
+ }
1547
+ }
1548
+ if ($rotation && in_array(abs($rotation), array(90, 180, 270))) {
1549
+ $thumbnail->rotateImageAngle($rotation);
1550
+ $remove_orientation_exif = TRUE;
1551
+ } else {
1552
+ $remove_orientation_exif = FALSE;
1553
+ }
1554
+ $flip = strtolower($flip);
1555
+ if ($flip && in_array($flip, array('h', 'v', 'hv'))) {
1556
+ $flip_h = in_array($flip, array('h', 'hv'));
1557
+ $flip_v = in_array($flip, array('v', 'hv'));
1558
+ $thumbnail->flipImage($flip_h, $flip_v);
1559
+ }
1560
+ if ($reflection) {
1561
+ $thumbnail->createReflection(40, 40, 50, FALSE, '#a4a4a4');
1562
+ }
1563
+ if ($clone_format != null && isset($format_list[$clone_format])) {
1564
+ // Force format
1565
+ $thumbnail->format = strtoupper($format_list[$clone_format]);
1566
+ }
1567
+ $thumbnail = apply_filters('ngg_before_save_thumbnail', $thumbnail);
1568
+ // Always retrieve metadata from the backup when possible
1569
+ $backup_path = $image_path . '_backup';
1570
+ $exif_abspath = @file_exists($backup_path) ? $backup_path : $image_path;
1571
+ $exif_iptc = @C_Exif_Writer::read_metadata($exif_abspath);
1572
+ $thumbnail->save($destpath, $quality);
1573
+ @C_Exif_Writer::write_metadata($destpath, $exif_iptc);
1574
+ }
1575
  }
1576
+ return $thumbnail;
1577
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1578
  /**
1579
+ * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated
1580
+ * @param string $image_path
1581
+ * @param string $clone_path
1582
+ * @param array $params
1583
+ * @return null|array
 
1584
  */
1585
+ function calculate_image_clone_dimensions($image_path, $clone_path, $params)
1586
  {
1587
+ $retval = null;
1588
+ $result = $this->object->calculate_image_clone_result($image_path, $clone_path, $params);
1589
+ if ($result != null) {
1590
+ $retval = array('width' => $result['width'], 'height' => $result['height'], 'real_width' => $result['real_width'], 'real_height' => $result['real_height']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1591
  }
1592
+ return $retval;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1593
  }
1594
  /**
1595
+ * Returns an array of properties of a resulting clone image if and when generated
1596
+ * @param string $image_path
1597
+ * @param string $clone_path
1598
+ * @param array $params
1599
+ * @return null|array
1600
  */
1601
+ function calculate_image_clone_result($image_path, $clone_path, $params)
1602
  {
1603
+ $width = isset($params['width']) ? $params['width'] : NULL;
1604
+ $height = isset($params['height']) ? $params['height'] : NULL;
1605
+ $quality = isset($params['quality']) ? $params['quality'] : NULL;
1606
+ $type = isset($params['type']) ? $params['type'] : NULL;
1607
+ $crop = isset($params['crop']) ? $params['crop'] : NULL;
1608
+ $watermark = isset($params['watermark']) ? $params['watermark'] : NULL;
1609
+ $rotation = isset($params['rotation']) ? $params['rotation'] : NULL;
1610
+ $reflection = isset($params['reflection']) ? $params['reflection'] : NULL;
1611
+ $crop_frame = isset($params['crop_frame']) ? $params['crop_frame'] : NULL;
1612
+ $result = NULL;
1613
+ // Ensure we have a valid image
1614
+ if ($image_path && @file_exists($image_path)) {
1615
+ // Ensure target directory exists, but only create 1 subdirectory
1616
+ $image_dir = dirname($image_path);
1617
+ $clone_dir = dirname($clone_path);
1618
+ $image_extension = M_I18n::mb_pathinfo($image_path, PATHINFO_EXTENSION);
1619
+ $image_extension_str = null;
1620
+ $clone_extension = M_I18n::mb_pathinfo($clone_path, PATHINFO_EXTENSION);
1621
+ $clone_extension_str = null;
1622
+ if ($image_extension != null) {
1623
+ $image_extension_str = '.' . $image_extension;
1624
+ }
1625
+ if ($clone_extension != null) {
1626
+ $clone_extension_str = '.' . $clone_extension;
1627
+ }
1628
+ $image_basename = M_I18n::mb_basename($image_path);
1629
+ $clone_basename = M_I18n::mb_basename($clone_path);
1630
+ // We use a default suffix as passing in null as the suffix will make WordPress use a default
1631
+ $clone_suffix = null;
1632
+ $format_list = $this->object->get_image_format_list();
1633
+ $clone_format = null;
1634
+ // format is determined below and based on $type otherwise left to null
1635
+ // suffix is only used to reconstruct paths for image_resize function
1636
+ if (strpos($clone_basename, $image_basename) === 0) {
1637
+ $clone_suffix = substr($clone_basename, strlen($image_basename));
1638
+ }
1639
+ if ($clone_suffix != null && $clone_suffix[0] == '-') {
1640
+ // WordPress adds '-' on its own
1641
+ $clone_suffix = substr($clone_suffix, 1);
1642
+ }
1643
+ // Get original image dimensions
1644
+ $dimensions = getimagesize($image_path);
1645
+ if ($width == null && $height == null) {
1646
+ if ($dimensions != null) {
1647
+ if ($width == null) {
1648
+ $width = $dimensions[0];
1649
+ }
1650
+ if ($height == null) {
1651
+ $height = $dimensions[1];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1652
  }
1653
+ } else {
1654
+ // XXX Don't think there's any other option here but to fail miserably...use some hard-coded defaults maybe?
1655
+ return null;
1656
  }
1657
+ }
1658
+ if ($dimensions != null) {
1659
+ $dimensions_ratio = $dimensions[0] / $dimensions[1];
1660
+ if ($width == null) {
1661
+ $width = (int) round($height * $dimensions_ratio);
1662
+ if ($width == $dimensions[0] - 1) {
1663
+ $width = $dimensions[0];
1664
  }
1665
+ } else {
1666
+ if ($height == null) {
1667
+ $height = (int) round($width / $dimensions_ratio);
1668
+ if ($height == $dimensions[1] - 1) {
1669
+ $height = $dimensions[1];
1670
+ }
1671
  }
 
 
1672
  }
1673
+ if ($width > $dimensions[0]) {
1674
+ $width = $dimensions[0];
1675
+ }
1676
+ if ($height > $dimensions[1]) {
1677
+ $height = $dimensions[1];
1678
+ }
1679
+ $image_format = $dimensions[2];
1680
+ if ($type != null) {
1681
+ if (is_string($type)) {
1682
+ $type = strtolower($type);
1683
+ // Indexes in the $format_list array correspond to IMAGETYPE_XXX values appropriately
1684
+ if (($index = array_search($type, $format_list)) !== false) {
1685
+ $type = $index;
1686
+ if ($type != $image_format) {
1687
+ // Note: this only changes the FORMAT of the image but not the extension
1688
+ $clone_format = $type;
1689
+ }
 
 
 
 
 
 
 
 
 
 
1690
  }
1691
+ }
1692
+ }
1693
+ }
1694
+ if ($width == null || $height == null) {
1695
+ // Something went wrong...
1696
+ return null;
1697
+ }
1698
+ // We now need to estimate the 'quality' or level of compression applied to the original JPEG: *IF* the
1699
+ // original image has a quality lower than the $quality parameter we will end up generating a new image
1700
+ // that is MUCH larger than the original. 'Quality' as an EXIF or IPTC property is quite unreliable
1701
+ // and not all software honors or treats it the same way. This calculation is simple: just compare the size
1702
+ // that our image could become to what it currently is. '3' is important here as JPEG uses 3 bytes per pixel.
1703
+ //
1704
+ // First we attempt to use ImageMagick if we can; it has a more robust method of calculation.
1705
+ if (!empty($dimensions['mime']) && $dimensions['mime'] == 'image/jpeg') {
1706
+ $possible_quality = NULL;
1707
+ $try_image_magick = TRUE;
1708
+ if (function_exists('is_wpe') && ($dimensions[0] >= 8000 || $dimensions[1] >= 8000)) {
1709
+ $try_image_magick = FALSE;
1710
+ }
1711
+ if ($try_image_magick && extension_loaded('imagick') && class_exists('Imagick')) {
1712
+ $img = new Imagick($image_path);
1713
+ if (method_exists($img, 'getImageCompressionQuality')) {
1714
+ $possible_quality = $img->getImageCompressionQuality();
1715
+ }
1716
+ }
1717
+ // ImageMagick wasn't available so we guess it from the dimensions and filesize
1718
+ if ($possible_quality === NULL) {
1719
+ $filesize = filesize($image_path);
1720
+ $possible_quality = 101 - $width * $height * 3 / $filesize;
1721
+ }
1722
+ if ($possible_quality !== NULL && $possible_quality < $quality) {
1723
+ $quality = $possible_quality;
1724
+ }
1725
+ }
1726
+ $result['clone_path'] = $clone_path;
1727
+ $result['clone_directory'] = $clone_dir;
1728
+ $result['clone_suffix'] = $clone_suffix;
1729
+ $result['clone_format'] = $clone_format;
1730
+ $result['base_width'] = $dimensions[0];
1731
+ $result['base_height'] = $dimensions[1];
1732
+ // image_resize() has limitations:
1733
+ // - no easy crop frame support
1734
+ // - fails if the dimensions are unchanged
1735
+ // - doesn't support filename prefix, only suffix so names like thumbs_original_name.jpg for $clone_path are not supported
1736
+ // also suffix cannot be null as that will make WordPress use a default suffix...we could use an object that returns empty string from __toString() but for now just fallback to ngg generator
1737
+ if (FALSE) {
1738
+ // disabling the WordPress method for Iteration #6
1739
+ // if (($crop_frame == null || !$crop) && ($dimensions[0] != $width && $dimensions[1] != $height) && $clone_suffix != null)
1740
+ $result['method'] = 'wordpress';
1741
+ $new_dims = image_resize_dimensions($dimensions[0], $dimensions[1], $width, $height, $crop);
1742
+ if ($new_dims) {
1743
+ list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $new_dims;
1744
+ $width = $dst_w;
1745
+ $height = $dst_h;
1746
+ } else {
1747
+ $result['error'] = new WP_Error('error_getting_dimensions', __('Could not calculate resized image dimensions'));
1748
+ }
1749
+ } else {
1750
+ $result['method'] = 'nextgen';
1751
+ $original_width = $dimensions[0];
1752
+ $original_height = $dimensions[1];
1753
+ $aspect_ratio = $width / $height;
1754
+ $orig_ratio_x = $original_width / $width;
1755
+ $orig_ratio_y = $original_height / $height;
1756
+ if ($crop) {
1757
+ $algo = 'shrink';
1758
+ // either 'adapt' or 'shrink'
1759
+ if ($crop_frame != null) {
1760
+ $crop_x = (int) round($crop_frame['x']);
1761
+ $crop_y = (int) round($crop_frame['y']);
1762
+ $crop_width = (int) round($crop_frame['width']);
1763
+ $crop_height = (int) round($crop_frame['height']);
1764
+ $crop_final_width = (int) round($crop_frame['final_width']);
1765
+ $crop_final_height = (int) round($crop_frame['final_height']);
1766
+ $crop_width_orig = $crop_width;
1767
+ $crop_height_orig = $crop_height;
1768
+ $crop_factor_x = $crop_width / $crop_final_width;
1769
+ $crop_factor_y = $crop_height / $crop_final_height;
1770
+ $crop_ratio_x = $crop_width / $width;
1771
+ $crop_ratio_y = $crop_height / $height;
1772
+ if ($algo == 'adapt') {
1773
+ // XXX not sure about this...don't use for now
1774
+ # $crop_width = (int) round($width * $crop_factor_x);
1775
+ # $crop_height = (int) round($height * $crop_factor_y);
1776
+ } else {
1777
+ if ($algo == 'shrink') {
1778
+ if ($crop_ratio_x < $crop_ratio_y) {
1779
+ $crop_width = max($crop_width, $width);
1780
+ $crop_height = (int) round($crop_width / $aspect_ratio);
1781
+ } else {
1782
+ $crop_height = max($crop_height, $height);
1783
+ $crop_width = (int) round($crop_height * $aspect_ratio);
1784
+ }
1785
+ if ($crop_width == $crop_width_orig - 1) {
1786
+ $crop_width = $crop_width_orig;
1787
+ }
1788
+ if ($crop_height == $crop_height_orig - 1) {
1789
+ $crop_height = $crop_height_orig;
1790
+ }
1791
+ }
1792
  }
1793
+ $crop_diff_x = (int) round(($crop_width_orig - $crop_width) / 2);
1794
+ $crop_diff_y = (int) round(($crop_height_orig - $crop_height) / 2);
1795
+ $crop_x += $crop_diff_x;
1796
+ $crop_y += $crop_diff_y;
1797
+ $crop_max_x = $crop_x + $crop_width;
1798
+ $crop_max_y = $crop_y + $crop_height;
1799
+ // Check if we're overflowing borders
1800
+ //
1801
+ if ($crop_x < 0) {
1802
+ $crop_x = 0;
1803
+ } else {
1804
+ if ($crop_max_x > $original_width) {
1805
+ $crop_x -= $crop_max_x - $original_width;
1806
+ }
1807
  }
1808
+ if ($crop_y < 0) {
1809
+ $crop_y = 0;
1810
+ } else {
1811
+ if ($crop_max_y > $original_height) {
1812
+ $crop_y -= $crop_max_y - $original_height;
1813
+ }
1814
+ }
1815
+ } else {
1816
+ if ($orig_ratio_x < $orig_ratio_y) {
1817
+ $crop_width = $original_width;
1818
+ $crop_height = (int) round($height * $orig_ratio_x);
1819
+ } else {
1820
+ $crop_height = $original_height;
1821
+ $crop_width = (int) round($width * $orig_ratio_y);
1822
+ }
1823
+ if ($crop_width == $width - 1) {
1824
+ $crop_width = $width;
1825
+ }
1826
+ if ($crop_height == $height - 1) {
1827
+ $crop_height = $height;
1828
+ }
1829
+ $crop_x = (int) round(($original_width - $crop_width) / 2);
1830
+ $crop_y = (int) round(($original_height - $crop_height) / 2);
1831
  }
1832
+ $result['crop_area'] = array('x' => $crop_x, 'y' => $crop_y, 'width' => $crop_width, 'height' => $crop_height);
 
 
 
 
 
1833
  } else {
1834
+ // Just constraint dimensions to ensure there's no stretching or deformations
1835
+ list($width, $height) = wp_constrain_dimensions($original_width, $original_height, $width, $height);
1836
  }
1837
+ }
1838
+ $result['width'] = $width;
1839
+ $result['height'] = $height;
1840
+ $result['quality'] = $quality;
1841
+ $real_width = $width;
1842
+ $real_height = $height;
1843
+ if ($rotation && in_array(abs($rotation), array(90, 270))) {
1844
+ $real_width = $height;
1845
+ $real_height = $width;
1846
+ }
1847
+ if ($reflection) {
1848
+ // default for nextgen was 40%, this is used in generate_image_clone as well
1849
+ $reflection_amount = 40;
1850
+ // Note, round() would probably be best here but using the same code that C_NggLegacy_Thumbnail uses for compatibility
1851
+ $reflection_height = intval($real_height * ($reflection_amount / 100));
1852
+ $real_height = $real_height + $reflection_height;
1853
+ }
1854
+ $result['real_width'] = $real_width;
1855
+ $result['real_height'] = $real_height;
1856
  }
1857
+ return $result;
1858
  }
1859
+ function generate_resized_image($image, $save = TRUE)
 
 
 
 
 
 
 
 
 
 
 
1860
  {
1861
+ $image_abspath = $this->object->get_image_abspath($image, 'full');
1862
+ $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full'));
1863
+ if ($generated && $save) {
1864
+ $this->object->update_image_dimension_metadata($image, $image_abspath);
1865
+ }
1866
+ if ($generated) {
1867
+ $generated->destruct();
1868
  }
 
1869
  }
1870
+ public function update_image_dimension_metadata($image, $image_abspath)
 
 
 
 
 
1871
  {
1872
+ // Ensure that fullsize dimensions are added to metadata array
1873
+ $dimensions = getimagesize($image_abspath);
1874
+ $full_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'md5' => $this->object->get_image_checksum($image, 'full'));
1875
+ if (!isset($image->meta_data) or is_string($image->meta_data) && strlen($image->meta_data) == 0 or is_bool($image->meta_data)) {
1876
+ $image->meta_data = array();
1877
  }
1878
+ $image->meta_data = array_merge($image->meta_data, $full_meta);
1879
+ $image->meta_data['full'] = $full_meta;
1880
+ // Don't forget to append the 'full' entry in meta_data in the db
1881
+ $this->object->_image_mapper->save($image);
1882
  }
1883
  /**
1884
+ * Most major browsers do not honor the Orientation meta found in EXIF. To prevent display issues we inspect
1885
+ * the EXIF data and rotate the image so that the EXIF field is not necessary to display the image correctly.
1886
+ * Note: generate_image_clone() will handle the removal of the Orientation tag inside the image EXIF.
1887
+ * Note: This only handles single-dimension rotation; at the time this method was written there are no known
1888
+ * camera manufacturers that both rotate and flip images.
1889
+ * @param $image
1890
+ * @param bool $save
1891
  */
1892
+ public function correct_exif_rotation($image, $save = TRUE)
1893
  {
1894
+ $image_abspath = $this->object->get_image_abspath($image, 'full');
1895
+ // This method is necessary
1896
+ if (!function_exists('exif_read_data')) {
1897
+ return;
1898
+ }
1899
+ // We only need to continue if the Orientation tag is set
1900
+ $exif = @exif_read_data($image_abspath, 'exif');
1901
+ if (empty($exif['Orientation']) || $exif['Orientation'] == 1) {
1902
+ return;
1903
+ }
1904
+ $degree = 0;
1905
+ if ($exif['Orientation'] == 3) {
1906
+ $degree = 180;
1907
+ }
1908
+ if ($exif['Orientation'] == 6) {
1909
+ $degree = 90;
1910
+ }
1911
+ if ($exif['Orientation'] == 8) {
1912
+ $degree = 270;
1913
+ }
1914
+ $parameters = array('rotation' => $degree);
1915
+ $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full', $parameters), $parameters);
1916
+ if ($generated && $save) {
1917
+ $this->object->update_image_dimension_metadata($image, $image_abspath);
1918
+ }
1919
+ if ($generated) {
1920
+ $generated->destruct();
1921
  }
 
1922
  }
1923
  /**
1924
+ * Flushes the cache we use for path/url calculation for galleries
 
 
 
1925
  */
1926
+ function flush_gallery_path_cache($gallery)
1927
  {
1928
+ $gallery = is_numeric($gallery) ? $gallery : $gallery->gid;
1929
+ unset(self::$gallery_abspath_cache[$gallery]);
1930
  }
1931
  /**
1932
+ * Gets the id of an image, regardless of whether an integer
1933
+ * or object was passed as an argument
1934
+ * @param object|int $image_obj_or_id
1935
+ * @return null|int
 
1936
  */
1937
+ function _get_image_id($image_obj_or_id)
1938
  {
1939
+ $retval = NULL;
1940
+ $image_key = $this->object->_image_mapper->get_primary_key_column();
1941
+ if (is_object($image_obj_or_id)) {
1942
+ if (isset($image_obj_or_id->{$image_key})) {
1943
+ $retval = $image_obj_or_id->{$image_key};
 
 
 
 
 
 
 
1944
  }
1945
+ } elseif (is_numeric($image_obj_or_id)) {
1946
+ $retval = $image_obj_or_id;
1947
  }
 
 
 
 
 
 
 
 
1948
  return $retval;
1949
  }
1950
  /**
1951
+ * Returns the absolute path to the cache directory of a gallery.
1952
  *
1953
+ * Without the gallery parameter the legacy (pre 2.0) shared directory is returned.
1954
+ *
1955
+ * @param int|object|false|C_Gallery $gallery (optional)
1956
+ * @return string Absolute path to cache directory
1957
  */
1958
+ function get_cache_abspath($gallery = FALSE)
1959
  {
1960
+ return path_join($this->object->get_gallery_abspath($gallery), 'cache');
1961
  }
1962
  /**
1963
+ * Gets the absolute path where the full-sized image is stored
1964
+ * @param int|object $image
1965
+ * @return null|string
1966
  */
1967
+ function get_full_abspath($image)
1968
  {
1969
+ return $this->object->get_image_abspath($image, 'full');
1970
  }
1971
  /**
1972
+ * Alias to get_image_dimensions()
1973
+ * @param int|object $image
1974
+ * @return array
 
 
 
1975
  */
1976
+ function get_full_dimensions($image)
1977
  {
1978
+ return $this->object->get_image_dimensions($image, 'full');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1979
  }
1980
  /**
1981
+ * Alias to get_image_html()
1982
+ * @param int|object $image
1983
+ * @return string
1984
  */
1985
+ function get_full_html($image)
1986
  {
1987
+ return $this->object->get_image_html($image, 'full');
1988
  }
1989
  /**
1990
+ * Alias for get_original_url()
1991
  *
1992
+ * @param int|stdClass|C_Image $image
1993
+ * @return string
1994
  */
1995
+ function get_full_url($image)
1996
  {
1997
+ return $this->object->get_image_url($image, 'full');
1998
+ }
1999
+ function get_gallery_root()
2000
+ {
2001
+ return wp_normalize_path(C_Fs::get_instance()->get_document_root('galleries'));
2002
+ }
2003
+ function _get_computed_gallery_abspath($gallery)
2004
+ {
2005
+ $retval = NULL;
2006
+ $gallery_root = $this->get_gallery_root();
2007
+ // Get the gallery entity from the database
2008
+ if ($gallery) {
2009
+ if (is_numeric($gallery)) {
2010
+ $gallery = $this->object->_gallery_mapper->find($gallery);
2011
+ }
2012
+ }
2013
+ // It just doesn't exist
2014
+ if (!$gallery) {
2015
+ return $retval;
2016
+ }
2017
+ // We we have a gallery, determine it's path
2018
+ if ($gallery) {
2019
+ if (isset($gallery->path)) {
2020
+ $retval = $gallery->path;
2021
+ } elseif (isset($gallery->slug)) {
2022
+ $basepath = wp_normalize_path(C_NextGen_Settings::get_instance()->gallerypath);
2023
+ $retval = path_join($basepath, $this->object->sanitize_directory_name(sanitize_title($gallery->slug)));
2024
+ }
2025
+ // Normalize the gallery path. If the gallery path starts with /wp-content, and
2026
+ // NGG_GALLERY_ROOT_TYPE is set to 'content', then we need to strip out the /wp-content
2027
+ // from the start of the gallery path
2028
+ if (NGG_GALLERY_ROOT_TYPE === 'content') {
2029
+ $retval = preg_replace("#^/?wp-content#", "", $retval);
2030
+ }
2031
+ // Ensure that the path is absolute
2032
+ if (strpos($retval, $gallery_root) !== 0) {
2033
+ // path_join() behaves funny - if the second argument starts with a slash,
2034
+ // it won't join the two paths together
2035
+ $retval = preg_replace("#^/#", "", $retval);
2036
+ $retval = path_join($gallery_root, $retval);
2037
+ }
2038
+ $retval = wp_normalize_path($retval);
2039
+ }
2040
+ return $retval;
2041
  }
2042
  /**
2043
+ * Get the abspath to the gallery folder for the given gallery
2044
+ * The gallery may or may not already be persisted
2045
+ * @param int|object|C_Gallery $gallery
2046
+ * @return string
2047
  */
2048
+ function get_gallery_abspath($gallery)
 
 
 
 
 
 
 
 
 
2049
  {
2050
+ $gallery_id = is_numeric($gallery) ? $gallery : (is_object($gallery) && isset($gallery->gid) ? $gallery->gid : NULL);
2051
+ if (!$gallery_id || !isset(self::$gallery_abspath_cache[$gallery_id])) {
2052
+ self::$gallery_abspath_cache[$gallery_id] = $this->object->_get_computed_gallery_abspath($gallery);
2053
+ }
2054
+ return self::$gallery_abspath_cache[$gallery_id];
2055
  }
2056
+ function get_gallery_relpath($gallery)
2057
  {
2058
+ // Special hack for home.pl: their document root is just '/'
2059
+ $root = $this->object->get_gallery_root();
2060
+ if ($root === '/') {
2061
+ return $this->get_gallery_abspath($gallery);
2062
+ }
2063
+ return str_replace($this->object->get_gallery_root(), '', $this->get_gallery_abspath($gallery));
2064
  }
2065
+ /**
2066
+ * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image.
2067
+ * @param int|object $image
2068
+ * @param string $size (optional) Default = full
2069
+ * @return string
2070
+ */
2071
+ function _get_computed_image_abspath($image, $size = 'full', $check_existance = FALSE)
2072
  {
2073
+ $retval = NULL;
2074
+ $fs = C_Fs::get_instance();
2075
+ // If we have the id, get the actual image entity
2076
+ if (is_numeric($image)) {
2077
+ $image = $this->object->_image_mapper->find($image);
2078
  }
2079
+ // Ensure we have the image entity - user could have passed in an
2080
+ // incorrect id
2081
+ if (is_object($image)) {
2082
+ if ($gallery_path = $this->object->get_gallery_abspath($image->galleryid)) {
2083
+ $folder = $prefix = $size;
2084
+ switch ($size) {
2085
+ # Images are stored in the associated gallery folder
2086
+ case 'full':
2087
+ $retval = path_join($gallery_path, $image->filename);
2088
+ break;
2089
+ case 'backup':
2090
+ $retval = path_join($gallery_path, $image->filename . '_backup');
2091
+ if (!@file_exists($retval)) {
2092
+ $retval = path_join($gallery_path, $image->filename);
2093
+ }
2094
+ break;
2095
+ case 'thumbnail':
2096
+ $size = 'thumbnail';
2097
+ $folder = 'thumbs';
2098
+ $prefix = 'thumbs';
2099
+ // deliberately no break here
2100
+ default:
2101
+ // NGG 2.0 stores relative filenames in the meta data of
2102
+ // an image. It does this because it uses filenames
2103
+ // that follow conventional WordPress naming scheme.
2104
+ $image_path = NULL;
2105
+ $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
2106
+ if (isset($image->meta_data) && isset($image->meta_data[$size]) && isset($image->meta_data[$size]['filename'])) {
2107
+ if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) {
2108
+ $image_path = path_join($this->object->get_cache_abspath($image->galleryid), $image->meta_data[$size]['filename']);
2109
+ } else {
2110
+ $image_path = path_join($gallery_path, $folder);
2111
+ $image_path = path_join($image_path, $image->meta_data[$size]['filename']);
2112
+ }
2113
+ } else {
2114
+ if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) {
2115
+ $params = $dynthumbs->get_params_from_name($size, true);
2116
+ $image_path = path_join($this->object->get_cache_abspath($image->galleryid), $dynthumbs->get_image_name($image, $params));
2117
+ // Filename is not found in meta, nor dynamic
2118
+ } else {
2119
+ $image_path = path_join($gallery_path, $folder);
2120
+ $image_path = path_join($image_path, "{$prefix}_{$image->filename}");
2121
+ }
2122
+ }
2123
+ $retval = $image_path;
2124
+ break;
2125
+ }
2126
+ }
2127
+ }
2128
+ if ($retval && $check_existance && !@file_exists($retval)) {
2129
+ $retval = NULL;
2130
  }
2131
+ return $retval;
2132
  }
2133
+ function get_image_checksum($image, $size = 'full')
2134
  {
2135
+ $retval = NULL;
2136
+ if ($image_abspath = $this->get_image_abspath($image, $size, TRUE)) {
2137
+ $retval = md5_file($image_abspath);
2138
+ }
2139
+ return $retval;
2140
  }
2141
  /**
2142
+ * Gets the dimensions for a particular-sized image
2143
  *
2144
+ * @param int|object $image
2145
+ * @param string $size
2146
+ * @return null|array
2147
  */
2148
+ function get_image_dimensions($image, $size = 'full')
2149
  {
2150
+ $retval = NULL;
2151
+ // If an image id was provided, get the entity
2152
+ if (is_numeric($image)) {
2153
+ $image = $this->object->_image_mapper->find($image);
2154
  }
2155
+ // Ensure we have a valid image
2156
+ if ($image) {
2157
+ $size = $this->normalize_image_size_name($size);
2158
+ if (!$size) {
2159
+ $size = 'full';
2160
+ }
2161
+ // Image dimensions are stored in the $image->meta_data
2162
+ // property for all implementations
2163
+ if (isset($image->meta_data) && isset($image->meta_data[$size])) {
2164
+ $retval = $image->meta_data[$size];
2165
+ } else {
2166
+ $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
2167
+ $abspath = $this->object->get_image_abspath($image, $size, TRUE);
2168
+ if ($abspath) {
2169
+ $dims = @getimagesize($abspath);
2170
+ if ($dims) {
2171
+ $retval['width'] = $dims[0];
2172
+ $retval['height'] = $dims[1];
2173
+ }
2174
+ } elseif ($size == 'backup') {
2175
+ $retval = $this->object->get_image_dimensions($image, 'full');
2176
+ }
2177
+ if (!$retval && $dynthumbs && $dynthumbs->is_size_dynamic($size)) {
2178
+ $new_dims = $this->object->calculate_image_size_dimensions($image, $size);
2179
+ $retval = array('width' => $new_dims['real_width'], 'height' => $new_dims['real_height']);
2180
+ }
2181
+ }
2182
+ }
2183
+ return $retval;
2184
  }
2185
+ function get_image_format_list()
2186
  {
2187
+ $format_list = array(IMAGETYPE_GIF => 'gif', IMAGETYPE_JPEG => 'jpg', IMAGETYPE_PNG => 'png');
2188
+ return $format_list;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2189
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2190
  /**
2191
+ * Gets the HTML for an image
2192
+ * @param int|object $image
2193
+ * @param string $size
2194
+ * @param array $attributes (optional)
2195
+ * @return string
2196
  */
2197
+ function get_image_html($image, $size = 'full', $attributes = array())
2198
  {
2199
+ $retval = "";
2200
  if (is_numeric($image)) {
2201
+ $image = $this->object->_image_mapper->find($image);
 
 
 
 
 
2202
  }
2203
+ if ($image) {
2204
+ // Set alt text if not already specified
2205
+ if (!isset($attributes['alttext'])) {
2206
+ $attributes['alt'] = esc_attr($image->alttext);
 
2207
  }
2208
+ // Set the title if not already set
2209
+ if (!isset($attributes['title'])) {
2210
+ $attributes['title'] = esc_attr($image->alttext);
2211
  }
2212
+ // Set the dimensions if not set already
2213
+ if (!isset($attributes['width']) or !isset($attributes['height'])) {
2214
+ $dimensions = $this->object->get_image_dimensions($image, $size);
2215
+ if (!isset($attributes['width'])) {
2216
+ $attributes['width'] = $dimensions['width'];
2217
+ }
2218
+ if (!isset($attributes['height'])) {
2219
+ $attributes['height'] = $dimensions['height'];
2220
+ }
2221
  }
2222
+ // Set the url if not already specified
2223
+ if (!isset($attributes['src'])) {
2224
+ $attributes['src'] = $this->object->get_image_url($image, $size);
2225
  }
2226
+ // Format attributes
2227
+ $attribs = array();
2228
+ foreach ($attributes as $attrib => $value) {
2229
+ $attribs[] = "{$attrib}=\"{$value}\"";
2230
+ }
2231
+ $attribs = implode(" ", $attribs);
2232
+ // Return HTML string
2233
+ $retval = "<img {$attribs} />";
2234
  }
2235
+ return $retval;
2236
  }
2237
+ function _get_computed_image_url($image, $size = 'full')
 
 
 
 
 
 
 
2238
  {
2239
+ $retval = NULL;
2240
+ $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
2241
+ // Get the image abspath
2242
+ $image_abspath = $this->object->get_image_abspath($image, $size);
2243
+ if ($dynthumbs->is_size_dynamic($size) && !file_exists($image_abspath)) {
2244
+ if (defined('NGG_DISABLE_DYNAMIC_IMG_URLS') && constant('NGG_DISABLE_DYNAMIC_IMG_URLS')) {
2245
+ $params = array('watermark' => false, 'reflection' => false, 'crop' => true);
2246
+ $result = $this->generate_image_size($image, $size, $params);
2247
+ if ($result) {
2248
+ $image_abspath = $this->object->get_image_abspath($image, $size);
2249
+ }
2250
+ } else {
2251
+ return NULL;
 
 
2252
  }
2253
  }
2254
+ // Assuming we have an abspath, we can translate that to a url
2255
+ if ($image_abspath) {
2256
+ // Replace the gallery root with the proper url segment
2257
+ $gallery_root = preg_quote($this->get_gallery_root(), '#');
2258
+ $image_uri = preg_replace("#^{$gallery_root}#", "", $image_abspath);
2259
+ // Url encode each uri segment
2260
+ $segments = explode("/", $image_uri);
2261
+ $segments = array_map('rawurlencode', $segments);
2262
+ $image_uri = preg_replace("#^/#", "", implode("/", $segments));
2263
+ // Join gallery root and image uri
2264
+ $gallery_root = trailingslashit(NGG_GALLERY_ROOT_TYPE == 'site' ? site_url() : WP_CONTENT_URL);
2265
+ $gallery_root = is_ssl() ? str_replace('http:', 'https:', $gallery_root) : $gallery_root;
2266
+ $retval = $gallery_root . $image_uri;
2267
  }
2268
+ return $retval;
2269
+ }
2270
+ function normalize_image_size_name($size = 'full')
2271
+ {
2272
+ switch ($size) {
2273
+ case 'full':
2274
+ case 'original':
2275
+ case 'image':
2276
+ case 'orig':
2277
+ case 'resized':
2278
+ $size = 'full';
2279
+ break;
2280
+ case 'thumbnails':
2281
+ case 'thumbnail':
2282
+ case 'thumb':
2283
+ case 'thumbs':
2284
+ $size = 'thumbnail';
2285
+ break;
2286
+ }
2287
+ return $size;
2288
  }
2289
  /**
2290
+ * Returns the named sizes available for images
2291
+ * @return array
 
 
2292
  */
2293
+ function get_image_sizes($image = FALSE)
2294
  {
2295
+ $retval = array('full', 'thumbnail');
2296
+ if (is_numeric($image)) {
2297
+ $image = C_Image_Mapper::get_instance()->find($image);
2298
  }
2299
+ if ($image) {
2300
+ if ($image->meta_data) {
2301
+ $meta_data = is_object($image->meta_data) ? get_object_vars($image->meta_data) : $image->meta_data;
2302
+ foreach ($meta_data as $key => $value) {
2303
+ if (is_array($value) && isset($value['width']) && !in_array($key, $retval)) {
2304
+ $retval[] = $key;
2305
+ }
2306
  }
2307
+ }
2308
+ }
2309
+ return $retval;
2310
+ }
2311
+ function get_image_size_params($image, $size, $params = array(), $skip_defaults = false)
2312
+ {
2313
+ // Get the image entity
2314
+ if (is_numeric($image)) {
2315
+ $image = $this->object->_image_mapper->find($image);
2316
+ }
2317
+ $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
2318
+ if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) {
2319
+ $named_params = $dynthumbs->get_params_from_name($size, true);
2320
+ if (!$params) {
2321
+ $params = array();
2322
+ }
2323
+ $params = array_merge($params, $named_params);
2324
+ }
2325
+ $params = apply_filters('ngg_get_image_size_params', $params, $size, $image);
2326
+ // Ensure we have a valid image
2327
+ if ($image) {
2328
+ $settings = C_NextGen_Settings::get_instance();
2329
+ if (!$skip_defaults) {
2330
+ // Get default settings
2331
+ if ($size == 'full') {
2332
+ if (!isset($params['quality'])) {
2333
+ $params['quality'] = $settings->imgQuality;
2334
+ }
2335
+ } else {
2336
+ if (!isset($params['crop'])) {
2337
+ $params['crop'] = $settings->thumbfix;
2338
+ }
2339
+ if (!isset($params['quality'])) {
2340
+ $params['quality'] = $settings->thumbquality;
2341
+ }
2342
  }
2343
+ }
2344
+ // width and height when omitted make generate_image_clone create a clone with original size, so try find defaults regardless of $skip_defaults
2345
+ if (!isset($params['width']) || !isset($params['height'])) {
2346
+ // First test if this is a "known" image size, i.e. if we store these sizes somewhere when users re-generate these sizes from the UI...this is required to be compatible with legacy
2347
+ // try the 2 default built-in sizes, first thumbnail...
2348
+ if ($size == 'thumbnail') {
2349
+ if (!isset($params['width'])) {
2350
+ $params['width'] = $settings->thumbwidth;
2351
+ }
2352
+ if (!isset($params['height'])) {
2353
+ $params['height'] = $settings->thumbheight;
2354
+ }
2355
  } else {
2356
+ if ($size == 'full') {
2357
+ if (!isset($params['width'])) {
2358
+ if ($settings->imgAutoResize) {
2359
+ $params['width'] = $settings->imgWidth;
2360
+ }
2361
+ }
2362
+ if (!isset($params['height'])) {
2363
+ if ($settings->imgAutoResize) {
2364
+ $params['height'] = $settings->imgHeight;
2365
+ }
2366
+ }
2367
  } else {
2368
+ if (isset($image->meta_data) && isset($image->meta_data[$size])) {
2369
+ $dimensions = $image->meta_data[$size];
2370
+ if (!isset($params['width'])) {
2371
+ $params['width'] = $dimensions['width'];
2372
+ }
2373
+ if (!isset($params['height'])) {
2374
+ $params['height'] = $dimensions['height'];
2375
+ }
2376
  }
2377
  }
2378
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2379
  }
2380
+ if (!isset($params['crop_frame'])) {
2381
+ $crop_frame_size_name = 'thumbnail';
2382
+ if (isset($image->meta_data[$size]['crop_frame'])) {
2383
+ $crop_frame_size_name = $size;
 
 
 
 
2384
  }
2385
+ if (isset($image->meta_data[$crop_frame_size_name]['crop_frame'])) {
2386
+ $params['crop_frame'] = $image->meta_data[$crop_frame_size_name]['crop_frame'];
2387
+ if (!isset($params['crop_frame']['final_width'])) {
2388
+ $params['crop_frame']['final_width'] = $image->meta_data[$crop_frame_size_name]['width'];
2389
+ }
2390
+ if (!isset($params['crop_frame']['final_height'])) {
2391
+ $params['crop_frame']['final_height'] = $image->meta_data[$crop_frame_size_name]['height'];
2392
+ }
2393
  }
2394
+ } else {
2395
+ if (!isset($params['crop_frame']['final_width'])) {
2396
+ $params['crop_frame']['final_width'] = $params['width'];
2397
  }
2398
+ if (!isset($params['crop_frame']['final_height'])) {
2399
+ $params['crop_frame']['final_height'] = $params['height'];
2400
  }
2401
  }
 
 
 
 
 
 
 
 
 
 
2402
  }
2403
+ return $params;
2404
  }
2405
+ /**
2406
+ * Alias to get_image_dimensions()
2407
+ * @param int|object $image
2408
+ * @return array
2409
+ */
2410
+ function get_original_dimensions($image)
2411
  {
2412
+ return $this->object->get_image_dimensions($image, 'full');
 
 
 
 
2413
  }
2414
+ /**
2415
+ * Alias to get_image_html()
2416
+ * @param int|object $image
2417
+ * @return string
2418
+ */
2419
+ function get_original_html($image)
2420
  {
2421
+ return $this->object->get_image_html($image, 'full');
 
 
 
 
 
 
2422
  }
2423
  /**
2424
+ * Gets the url to the original-sized image
2425
+ * @param int|stdClass|C_Image $image
2426
+ * @param bool $check_existance (optional)
2427
+ * @return string
2428
  */
2429
+ function get_original_url($image, $check_existance = FALSE)
2430
  {
2431
+ return $this->object->get_image_url($image, 'full', $check_existance);
2432
+ }
2433
+ /**
2434
+ * @param object|bool $gallery (optional)
2435
+ * @return string
2436
+ */
2437
+ function get_upload_abspath($gallery = FALSE)
2438
+ {
2439
+ // Base upload path
2440
+ $retval = C_NextGen_Settings::get_instance()->gallerypath;
2441
+ $fs = C_Fs::get_instance();
2442
+ // If a gallery has been specified, then we'll
2443
+ // append the slug
2444
+ if ($gallery) {
2445
+ $retval = $this->get_gallery_abspath($gallery);
 
 
2446
  }
2447
+ // We need to make this an absolute path
2448
+ if (strpos($retval, $fs->get_document_root('gallery')) !== 0) {
2449
+ $retval = rtrim($fs->join_paths($fs->get_document_root('gallery'), $retval), "/\\");
2450
  }
2451
+ // Convert slashes
2452
+ return wp_normalize_path($retval);
2453
  }
2454
  /**
2455
+ * Gets the upload path, optionally for a particular gallery
2456
+ * @param int|C_Gallery|object|false $gallery (optional)
2457
+ * @return string
 
 
 
2458
  */
2459
+ function get_upload_relpath($gallery = FALSE)
2460
  {
2461
+ $fs = C_Fs::get_instance();
2462
+ $retval = str_replace($fs->get_document_root('gallery'), '', $this->object->get_upload_abspath($gallery));
2463
+ return '/' . wp_normalize_path(ltrim($retval, "/"));
 
 
 
 
 
 
 
 
 
 
 
 
2464
  }
2465
  /**
2466
+ * Set correct file permissions (taken from wp core). Should be called
2467
+ * after writing any file
 
 
 
2468
  *
2469
+ * @class nggAdmin
2470
+ * @param string $filename
2471
+ * @return bool $result
2472
  */
2473
+ function _chmod($filename = '')
2474
  {
2475
+ $stat = @stat(dirname($filename));
2476
+ $perms = $stat['mode'] & 0666;
2477
+ // Remove execute bits for files
2478
+ if (@chmod($filename, $perms)) {
2479
+ return TRUE;
2480
  }
2481
+ return FALSE;
2482
+ }
2483
+ function _delete_gallery_directory($abspath)
2484
+ {
2485
+ // Remove all image files and purge all empty directories left over
2486
+ $iterator = new DirectoryIterator($abspath);
2487
+ // Only delete image files! Other files may be stored incorrectly but it's not our place to delete them
2488
+ $removable_extensions = apply_filters('ngg_allowed_file_types', array('jpeg', 'jpg', 'png', 'gif'));
2489
+ foreach ($removable_extensions as $extension) {
2490
+ $removable_extensions[] = $extension . '_backup';
2491
+ }
2492
+ foreach ($iterator as $file) {
2493
+ if (in_array($file->getBasename(), array('.', '..'))) {
2494
+ continue;
2495
+ } elseif ($file->isFile() || $file->isLink()) {
2496
+ $extension = strtolower(pathinfo($file->getPathname(), PATHINFO_EXTENSION));
2497
+ if (in_array($extension, $removable_extensions, TRUE)) {
2498
+ @unlink($file->getPathname());
2499
+ }
2500
+ } elseif ($file->isDir()) {
2501
+ $this->object->_delete_gallery_directory($file->getPathname());
2502
+ }
2503
+ }
2504
+ // DO NOT remove directories that still have files in them. Note: '.' and '..' are included with getSize()
2505
+ $empty = TRUE;
2506
+ foreach ($iterator as $file) {
2507
+ if (in_array($file->getBasename(), array('.', '..'))) {
2508
+ continue;
2509
+ }
2510
+ $empty = FALSE;
2511
+ }
2512
+ if ($empty) {
2513
+ @rmdir($iterator->getPath());
2514
+ }
2515
+ }
2516
+ /**
2517
+ * @param C_Image[]|int[] $images
2518
+ * @param C_Gallery|int $dst_gallery
2519
+ * @return int[]
2520
+ */
2521
+ function copy_images($images, $dst_gallery)
2522
+ {
2523
+ $retval = array();
2524
+ // Ensure that the image ids we have are valid
2525
+ $image_mapper = C_Image_Mapper::get_instance();
2526
+ foreach ($images as $image) {
2527
+ if (is_numeric($image)) {
2528
+ $image = $image_mapper->find($image);
2529
+ }
2530
+ if ($image_abspath = $this->object->get_image_abspath($image)) {
2531
+ // Import the image; this will copy the main file
2532
+ $new_image_id = $this->object->import_image_file($dst_gallery, $image_abspath, $image->filename);
2533
+ if ($new_image_id) {
2534
+ // Copy the properties of the old image
2535
+ $new_image = $image_mapper->find($new_image_id);
2536
+ foreach (get_object_vars($image) as $key => $value) {
2537
+ if (in_array($key, array('pid', 'galleryid', 'meta_data', 'filename', 'sortorder', 'extras_post_id'))) {
2538
+ continue;
2539
  }
2540
+ $new_image->{$key} = $value;
2541
+ }
2542
+ $image_mapper->save($new_image);
2543
+ // Copy tags
2544
+ $tags = wp_get_object_terms($image->pid, 'ngg_tag', 'fields=ids');
2545
+ $tags = array_map('intval', $tags);
2546
+ wp_set_object_terms($new_image_id, $tags, 'ngg_tag', true);
2547
+ // Copy all of the generated versions (resized versions, watermarks, etc)
2548
+ foreach ($this->object->get_image_sizes($image) as $named_size) {
2549
+ if (in_array($named_size, array('full', 'thumbnail'))) {
2550
  continue;
2551
  }
2552
+ $old_abspath = $this->object->get_image_abspath($image, $named_size);
2553
+ $new_abspath = $this->object->get_image_abspath($new_image, $named_size);
2554
+ if (is_array(@stat($old_abspath))) {
2555
+ $new_dir = dirname($new_abspath);
2556
+ // Ensure the target directory exists
2557
+ if (@stat($new_dir) === FALSE) {
2558
+ wp_mkdir_p($new_dir);
2559
+ }
2560
+ @copy($old_abspath, $new_abspath);
 
2561
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2562
  }
2563
+ // Mark as done
2564
+ $retval[] = $new_image_id;
2565
  }
2566
  }
2567
  }
2568
+ return $retval;
 
 
 
 
 
 
 
 
2569
  }
2570
+ /**
2571
+ * Moves images from to another gallery
2572
+ * @param array $images
2573
+ * @param int|object $gallery
2574
+ * @return int[]
2575
+ */
2576
+ function move_images($images, $gallery)
2577
  {
2578
+ $retval = $this->object->copy_images($images, $gallery);
2579
+ if ($images) {
2580
+ foreach ($images as $image_id) {
2581
+ $this->object->delete_image($image_id);
2582
+ }
 
2583
  }
2584
+ return $retval;
2585
  }
2586
  /**
2587
+ * @param string $abspath
2588
+ * @return bool
 
 
2589
  */
2590
+ function delete_directory($abspath)
2591
  {
2592
+ $retval = FALSE;
2593
+ if (@file_exists($abspath)) {
2594
+ $files = scandir($abspath);
2595
+ array_shift($files);
2596
+ array_shift($files);
2597
+ foreach ($files as $file) {
2598
+ $file_abspath = implode(DIRECTORY_SEPARATOR, array(rtrim($abspath, "/\\"), $file));
2599
+ if (is_dir($file_abspath)) {
2600
+ $this->object->delete_directory($file_abspath);
2601
+ } else {
2602
+ unlink($file_abspath);
2603
+ }
2604
+ }
2605
+ rmdir($abspath);
2606
+ $retval = @file_exists($abspath);
2607
  }
2608
+ return $retval;
2609
+ }
2610
+ function delete_gallery($gallery)
2611
+ {
2612
+ $fs = C_Fs::get_instance();
2613
+ $safe_dirs = array(DIRECTORY_SEPARATOR, $fs->get_document_root('plugins'), $fs->get_document_root('plugins_mu'), $fs->get_document_root('templates'), $fs->get_document_root('stylesheets'), $fs->get_document_root('content'), $fs->get_document_root('galleries'), $fs->get_document_root());
2614
+ $abspath = $this->object->get_gallery_abspath($gallery);
2615
+ if ($abspath && file_exists($abspath) && !in_array(stripslashes($abspath), $safe_dirs)) {
2616
+ $this->object->_delete_gallery_directory($abspath);
2617
  }
2618
+ }
2619
+ function delete_image($image, $size = FALSE)
2620
+ {
2621
+ $retval = FALSE;
2622
+ // Ensure that we have the image entity
2623
+ if (is_numeric($image)) {
2624
+ $image = $this->object->_image_mapper->find($image);
2625
  }
2626
+ if ($image) {
2627
+ $image_id = $image->{$image->id_field};
2628
+ do_action('ngg_delete_image', $image_id, $size);
2629
+ // Delete only a particular image size
2630
+ if ($size) {
2631
+ $abspath = $this->object->get_image_abspath($image, $size);
2632
+ if ($abspath && @file_exists($abspath)) {
2633
+ @unlink($abspath);
2634
+ }
2635
+ if (isset($image->meta_data) && isset($image->meta_data[$size])) {
2636
+ unset($image->meta_data[$size]);
2637
+ $this->object->_image_mapper->save($image);
2638
+ }
2639
+ } else {
2640
+ foreach ($this->object->get_image_sizes($image) as $named_size) {
2641
+ $image_abspath = $this->object->get_image_abspath($image, $named_size);
2642
+ @unlink($image_abspath);
2643
+ }
2644
+ // Delete the entity
2645
+ $this->object->_image_mapper->destroy($image);
2646
+ }
2647
+ $retval = TRUE;
2648
  }
2649
+ return $retval;
 
2650
  }
2651
  /**
2652
+ * Recover image from backup copy and reprocess it
2653
  *
2654
+ * @param int|stdClass|C_Image $image
2655
+ * @return bool|string result code
2656
  */
2657
+ function recover_image($image)
2658
  {
2659
+ $retval = FALSE;
2660
+ if (is_numeric($image)) {
2661
+ $image = $this->object->_image_mapper->find($image);
2662
  }
2663
+ if ($image) {
2664
+ $full_abspath = $this->object->get_image_abspath($image);
2665
+ $backup_abspath = $this->object->get_image_abspath($image, 'backup');
2666
+ if ($backup_abspath != $full_abspath && @file_exists($backup_abspath)) {
2667
+ if (is_writable($full_abspath) && is_writable(dirname($full_abspath))) {
2668
+ // Copy the backup
2669
+ if (@copy($backup_abspath, $full_abspath)) {
2670
+ // Backup images are not altered at all; we must re-correct the EXIF/Orientation tag
2671
+ $this->object->correct_exif_rotation($image, TRUE);
2672
+ // Re-create non-fullsize image sizes
2673
+ foreach ($this->object->get_image_sizes($image) as $named_size) {
2674
+ if (in_array($named_size, array('full', 'backup'))) {
2675
+ continue;
2676
+ }
2677
+ // Reset thumbnail cropping set by 'Edit thumb' dialog
2678
+ if ($named_size === 'thumbnail') {
2679
+ unset($image->meta_data[$named_size]['crop_frame']);
2680
+ }
2681
+ $thumbnail = $this->object->generate_image_clone($full_abspath, $this->object->get_image_abspath($image, $named_size), $this->object->get_image_size_params($image, $named_size));
2682
+ if ($thumbnail) {
2683
+ $thumbnail->destruct();
2684
+ }
2685
+ }
2686
+ do_action('ngg_recovered_image', $image);
2687
+ // Reimport all metadata
2688
+ $retval = $this->object->_image_mapper->reimport_metadata($image);
2689
+ }
2690
+ }
2691
+ }
2692
+ }
2693
+ return $retval;
2694
  }
2695
  /**
2696
+ * Copies a NGG image to the media library and returns the attachment_id
2697
+ *
2698
+ * @param C_Image|int|stdClass $image
2699
+ * @return FALSE|int attachment_id
2700
  */
2701
+ function copy_to_media_library($image)
2702
  {
2703
+ $retval = FALSE;
2704
+ // Get the image
2705
+ if (is_int($image)) {
2706
+ $imageId = $image;
2707
+ $mapper = C_Image_Mapper::get_instance();
2708
+ $image = $mapper->find($imageId);
2709
  }
2710
+ if ($image) {
2711
+ $subdir = apply_filters('ngg_import_to_media_library_subdir', 'nggallery_import');
2712
+ $wordpress_upload_dir = wp_upload_dir();
2713
+ $path = $wordpress_upload_dir['path'] . DIRECTORY_SEPARATOR . $subdir;
2714
+ if (!file_exists($path)) {
2715
+ wp_mkdir_p($path);
2716
+ }
2717
+ $image_abspath = C_Gallery_Storage::get_instance()->get_image_abspath($image, "full");
2718
+ $new_file_path = $path . DIRECTORY_SEPARATOR . $image->filename;
2719
+ $image_data = getimagesize($image_abspath);
2720
+ $new_file_mime = $image_data['mime'];
2721
+ $i = 1;
2722
+ while (file_exists($new_file_path)) {
2723
+ $i++;
2724
+ $new_file_path = $path . DIRECTORY_SEPARATOR . $i . '_' . $image->filename;
2725
+ }
2726
+ if (@copy($image_abspath, $new_file_path)) {
2727
+ $upload_id = wp_insert_attachment(['guid' => $new_file_path, 'post_mime_type' => $new_file_mime, 'post_title' => preg_replace('/\\.[^.]+$/', '', $image->alttext), 'post_content' => '', 'post_status' => 'inherit'], $new_file_path);
2728
+ update_post_meta($upload_id, '_ngg_image_id', intval($image->pid));
2729
+ // wp_generate_attachment_metadata() comes from this file
2730
+ require_once ABSPATH . 'wp-admin/includes/image.php';
2731
+ $image_meta = wp_generate_attachment_metadata($upload_id, $new_file_path);
2732
+ // Generate and save the attachment metas into the database
2733
+ wp_update_attachment_metadata($upload_id, $image_meta);
2734
+ $retval = $upload_id;
2735
+ }
2736
  }
2737
+ return $retval;
 
 
2738
  }
2739
  /**
2740
+ * Delete the given NGG image from the media library
 
2741
  *
2742
+ * @var int|stdClass $imageId
 
2743
  */
2744
+ function delete_from_media_library($imageId)
2745
  {
2746
+ // Get the image
2747
+ if (!is_int($imageId)) {
2748
+ $image = $imageId;
2749
+ $imageId = $image->pid;
 
 
2750
  }
2751
+ if ($postId = $this->object->is_in_media_library($imageId)) {
2752
+ wp_delete_post($postId);
2753
  }
 
 
 
 
2754
  }
2755
  /**
2756
+ * Determines if the given NGG image id has been uploaded to the media library
2757
  *
2758
+ * @param integer $imageId
2759
+ * @return FALSE|int attachment_id
2760
  */
2761
+ function is_in_media_library($imageId)
2762
  {
2763
+ $retval = FALSE;
2764
+ // Get the image
2765
+ if (is_object($imageId)) {
2766
+ $image = $imageId;
2767
+ $imageId = $image->pid;
2768
+ }
2769
+ // Try to find an attachment for the given image_id
2770
+ if ($imageId) {
2771
+ $query = new WP_Query(array('post_type' => 'attachment', 'meta_key' => '_ngg_image_id', 'meta_value_num' => $imageId));
2772
+ foreach ($query->get_posts() as $post) {
2773
+ $retval = $post->ID;
2774
+ }
2775
+ }
2776
+ return $retval;
2777
  }
2778
  /**
2779
+ * @param string $filename
2780
+ * @return bool
 
 
 
 
 
 
2781
  */
2782
+ public function is_allowed_image_extension($filename)
2783
  {
2784
+ $extension = pathinfo($filename, PATHINFO_EXTENSION);
2785
+ $extension = strtolower($extension);
2786
+ $allowed_extensions = apply_filters('ngg_allowed_file_types', array('jpeg', 'jpg', 'png', 'gif'));
2787
+ foreach ($allowed_extensions as $extension) {
2788
+ $allowed_extensions[] = $extension . '_backup';
 
 
 
 
 
 
 
2789
  }
2790
+ return in_array($extension, $allowed_extensions);
2791
+ }
2792
+ function is_current_user_over_quota()
2793
+ {
2794
+ $retval = FALSE;
2795
+ $settings = C_NextGen_Settings::get_instance();
2796
+ if (is_multisite() && $settings->get('wpmuQuotaCheck')) {
2797
+ require_once ABSPATH . 'wp-admin/includes/ms.php';
2798
+ $retval = upload_is_user_over_quota(FALSE);
2799
+ }
2800
+ return $retval;
2801
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2802
  /**
2803
+ * @param string? $filename
2804
+ * @return bool
 
 
2805
  */
2806
+ function is_image_file($filename = NULL)
2807
  {
2808
+ $retval = FALSE;
2809
+ if (!$filename && isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
2810
+ $filename = $_FILES['file']['tmp_name'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2811
  }
2812
+ $valid_types = array('image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png');
2813
+ // If we can, we'll verify the mime type
2814
+ if (function_exists('exif_imagetype')) {
2815
+ if (($image_type = @exif_imagetype($filename)) !== FALSE) {
2816
+ $retval = in_array(image_type_to_mime_type($image_type), $valid_types);
2817
+ }
2818
+ } else {
2819
+ $file_info = @getimagesize($filename);
2820
+ if (isset($file_info[2])) {
2821
+ $retval = in_array(image_type_to_mime_type($file_info[2]), $valid_types);
2822
+ }
2823
  }
2824
+ return $retval;
2825
+ }
2826
+ function is_zip()
2827
+ {
2828
+ $retval = FALSE;
2829
+ if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
2830
+ $file_info = $_FILES['file'];
2831
+ if (isset($file_info['type'])) {
2832
+ $type = $file_info['type'];
2833
+ $type_parts = explode('/', $type);
2834
+ if (strtolower($type_parts[0]) == 'application') {
2835
+ $spec = $type_parts[1];
2836
+ $spec_parts = explode('-', $spec);
2837
+ $spec_parts = array_map('strtolower', $spec_parts);
2838
+ if (in_array($spec, array('zip', 'octet-stream')) || in_array('zip', $spec_parts)) {
2839
+ $retval = true;
 
 
 
 
 
 
 
2840
  }
 
 
 
 
 
2841
  }
 
 
 
 
 
2842
  }
2843
  }
2844
+ return $retval;
2845
+ }
2846
+ function maybe_base64_decode($data)
2847
+ {
2848
+ $decoded = base64_decode($data);
2849
+ if ($decoded === FALSE) {
2850
+ return $data;
2851
+ } else {
2852
+ if (base64_encode($decoded) == $data) {
2853
+ return base64_decode($data);
2854
  }
 
2855
  }
2856
+ return $data;
2857
  }
2858
+ function get_unique_abspath($file_abspath)
 
 
 
 
 
2859
  {
2860
+ $filename = basename($file_abspath);
2861
+ $dir_abspath = dirname($file_abspath);
2862
+ $num = 1;
2863
+ $pattern = path_join($dir_abspath, "*_{$filename}");
2864
+ if ($found = glob($pattern)) {
2865
+ natsort($found);
2866
+ $last = array_pop($found);
2867
+ $last = basename($last);
2868
+ if (preg_match("/^(\\d+)_/", $last, $match)) {
2869
+ $num = intval($match[1]) + 1;
2870
+ }
 
 
2871
  }
2872
+ return path_join($dir_abspath, "{$num}_{$filename}");
 
 
2873
  }
2874
+ function sanitize_filename_for_db($filename = NULL)
2875
  {
2876
+ $filename = $filename ? $filename : uniqid('nextgen-gallery');
2877
+ $filename = preg_replace("#^/#", "", $filename);
2878
+ $filename = sanitize_file_name($filename);
2879
+ if (preg_match("/\\-(png|jpg|gif|jpeg|jpg_backup)\$/i", $filename, $match)) {
2880
+ $filename = str_replace($match[0], '.' . $match[1], $filename);
 
 
 
 
 
 
 
 
 
 
2881
  }
2882
+ return $filename;
2883
+ }
2884
+ function import_image_file($dst_gallery, $image_abspath, $filename = NULL, $image = FALSE, $override = FALSE, $move = FALSE)
2885
+ {
2886
+ $image_abspath = wp_normalize_path($image_abspath);
2887
+ if ($this->object->is_current_user_over_quota()) {
2888
+ $message = sprintf(__('Sorry, you have used your space allocation. Please delete some files to upload more files.', 'nggallery'));
2889
+ throw new E_NoSpaceAvailableException($message);
2890
  }
2891
+ // Do we have a gallery to import to?
2892
+ if ($dst_gallery) {
2893
+ // Get the gallery abspath. This is where we will put the image files
2894
+ $gallery_abspath = $this->object->get_gallery_abspath($dst_gallery);
2895
+ // If we can't write to the directory, then there's no point in continuing
2896
+ if (!@file_exists($gallery_abspath)) {
2897
+ @wp_mkdir_p($gallery_abspath);
 
 
 
 
 
 
 
 
2898
  }
2899
+ if (!is_writable($gallery_abspath)) {
2900
+ throw new E_InsufficientWriteAccessException(FALSE, $gallery_abspath, FALSE);
2901
+ }
2902
+ // Sanitize the filename for storing in the DB
2903
+ $filename = $this->sanitize_filename_for_db($filename);
2904
+ // Ensure that the filename is valid
2905
+ if (!preg_match("/(png|jpeg|jpg|gif|_backup)\$/i", $filename)) {
2906
+ throw new E_UploadException(__('Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery'));
2907
+ }
2908
+ // Compute the destination folder
2909
+ $new_image_abspath = path_join($gallery_abspath, $filename);
2910
+ // Are the src and dst the same? If so, we don't have to copy or move files
2911
+ if ($image_abspath != $new_image_abspath) {
2912
+ // If we're not to override, ensure that the filename is unique
2913
+ if (!$override && @file_exists($new_image_abspath)) {
2914
+ $new_image_abspath = $this->object->get_unique_abspath($new_image_abspath);
2915
+ $filename = $this->sanitize_filename_for_db(basename($new_image_abspath));
2916
  }
2917
+ // Try storing the file
2918
+ $copied = copy($image_abspath, $new_image_abspath);
2919
+ if ($copied && $move) {
2920
+ unlink($image_abspath);
2921
+ }
2922
+ // Ensure that we're not vulerable to CVE-2017-2416 exploit
2923
+ if (($dimensions = getimagesize($new_image_abspath)) !== FALSE) {
2924
+ if (isset($dimensions[0]) && intval($dimensions[0]) > 30000 || isset($dimensions[1]) && intval($dimensions[1]) > 30000) {
2925
+ unlink($new_image_abspath);
2926
+ throw new E_UploadException(__('Image file too large. Maximum image dimensions supported are 30k x 30k.'));
2927
+ }
2928
+ }
2929
+ }
2930
+ // Save the image in the DB
2931
+ $image_mapper = C_Image_Mapper::get_instance();
2932
+ $image_mapper->_use_cache = FALSE;
2933
+ if ($image) {
2934
+ if (is_numeric($image)) {
2935
+ $image = $image_mapper->find($image);
2936
+ }
2937
+ }
2938
+ if (!$image) {
2939
+ $image = $image_mapper->create();
2940
+ }
2941
+ $image->alttext = preg_replace("#\\.\\w{2,4}\$#", "", $filename);
2942
+ $image->galleryid = is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid;
2943
+ $image->filename = $filename;
2944
+ $image->image_slug = nggdb::get_unique_slug(sanitize_title_with_dashes($image->alttext), 'image');
2945
+ $image_id = $image_mapper->save($image);
2946
+ if (!$image_id) {
2947
+ $exception = '';
2948
+ foreach ($image->get_errors() as $field => $errors) {
2949
+ foreach ($errors as $error) {
2950
+ if (!empty($exception)) {
2951
+ $exception .= "<br/>";
2952
+ }
2953
+ $exception .= __(sprintf("Error while uploading %s: %s", $filename, $error), 'nextgen-gallery');
2954
+ }
2955
  }
2956
+ throw new E_UploadException($exception);
2957
+ }
2958
+ // Important: do not remove this line. The image mapper's save() routine imports metadata
2959
+ // meaning we must re-acquire a new $image object after saving it above; if we do not our
2960
+ // existing $image object will lose any metadata retrieved during said save() method.
2961
+ $image = $image_mapper->find($image_id);
2962
+ $image_mapper->_use_cache = TRUE;
2963
+ $settings = C_NextGen_Settings::get_instance();
2964
+ // Backup the image
2965
+ if ($settings->get('imgBackup', FALSE)) {
2966
+ $this->object->backup_image($image, TRUE);
2967
+ }
2968
+ // Most browsers do not honor EXIF's Orientation header: rotate the image to prevent display issues
2969
+ $this->object->correct_exif_rotation($image, TRUE);
2970
+ // Create resized version of image
2971
+ if ($settings->get('imgAutoResize', FALSE)) {
2972
+ $this->object->generate_resized_image($image, TRUE);
2973
+ }
2974
+ // Generate a thumbnail for the image
2975
+ $this->object->generate_thumbnail($image);
2976
+ // Set gallery preview image if missing
2977
+ C_Gallery_Mapper::get_instance()->set_preview_image($dst_gallery, $image_id, TRUE);
2978
+ // Automatically watermark the main image if requested
2979
+ if ($settings->get('watermark_automatically_at_upload', 0)) {
2980
+ $image_abspath = $this->object->get_image_abspath($image, 'full');
2981
+ $this->object->generate_image_clone($image_abspath, $image_abspath, array('watermark' => TRUE));
2982
  }
2983
+ // Notify other plugins that an image has been added
2984
+ do_action('ngg_added_new_image', $image);
2985
+ // delete dirsize after adding new images
2986
+ delete_transient('dirsize_cache');
2987
+ // Seems redundant to above hook. Maintaining for legacy purposes
2988
+ do_action('ngg_after_new_images_added', is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid, array($image_id));
2989
+ return $image_id;
2990
+ } else {
2991
+ throw new E_EntityNotFoundException();
2992
  }
2993
+ return NULL;
 
 
 
 
2994
  }
2995
  /**
2996
+ * Uploads base64 file to a gallery
2997
+ * @param int|stdClass|C_Gallery $gallery
2998
+ * @param $data base64-encoded string of data representing the image
2999
+ * @param string|false (optional) $filename specifies the name of the file
3000
+ * @param int|false $image_id (optional)
3001
+ * @param bool $override (optional)
3002
+ * @return C_Image
3003
  */
3004
+ function upload_base64_image($gallery, $data, $filename = FALSE, $image_id = FALSE, $override = FALSE, $move = FALSE)
3005
  {
3006
+ try {
3007
+ $temp_abspath = tempnam(sys_get_temp_dir(), '');
3008
+ // Try writing the image
3009
+ $fp = fopen($temp_abspath, 'wb');
3010
+ fwrite($fp, $this->maybe_base64_decode($data));
3011
+ fclose($fp);
3012
+ } catch (E_UploadException $ex) {
3013
+ throw $ex;
3014
  }
3015
+ return $this->object->import_image_file($gallery, $temp_abspath, $filename, $image_id, $override, $move);
3016
  }
3017
  /**
3018
+ * Uploads an image for a particular gallery
3019
+ * @param int|object|C_Gallery $gallery
3020
+ * @param string|bool $filename (optional) Specifies the name of the file
3021
+ * @param string|bool $data (optional) If specified, expects base64 encoded string of data
3022
+ * @return C_Image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3023
  */
3024
+ function upload_image($gallery, $filename = FALSE, $data = FALSE)
3025
  {
3026
+ $retval = NULL;
3027
+ // Ensure that we have the data present that we require
3028
+ if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
3029
+ // $_FILES = Array(
3030
+ // [file] => Array (
3031
+ // [name] => Canada_landscape4.jpg
3032
+ // [type] => image/jpeg
3033
+ // [tmp_name] => /private/var/tmp/php6KO7Dc
3034
+ // [error] => 0
3035
+ // [size] => 64975
3036
+ // )
3037
+ //
3038
+ $file = $_FILES['file'];
3039
+ if ($this->object->is_zip()) {
3040
+ $retval = $this->object->upload_zip($gallery);
3041
+ } else {
3042
+ if ($this->is_image_file()) {
3043
+ $retval = $this->object->import_image_file($gallery, $file['tmp_name'], $filename ? $filename : (isset($file['name']) ? $file['name'] : FALSE), FALSE, FALSE, TRUE);
3044
+ } else {
3045
+ // Remove the non-valid (and potentially insecure) file from the PHP upload directory
3046
+ if (isset($_FILES['file']['tmp_name'])) {
3047
+ $filename = $_FILES['file']['tmp_name'];
3048
+ @unlink($filename);
3049
+ }
3050
+ throw new E_UploadException(__('Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery'));
3051
+ }
3052
+ }
3053
+ } elseif ($data) {
3054
+ $retval = $this->object->upload_base64_image($gallery, $data, $filename);
3055
+ } else {
3056
+ throw new E_UploadException();
3057
  }
3058
+ return $retval;
3059
  }
3060
  /**
3061
+ * @param int $gallery_id
3062
+ * @return array|bool
 
 
 
3063
  */
3064
+ function upload_zip($gallery_id)
3065
  {
3066
+ if (!$this->object->is_zip()) {
3067
+ return FALSE;
 
 
3068
  }
3069
+ $retval = FALSE;
3070
+ $memory_limit = intval(ini_get('memory_limit'));
3071
+ if (!extension_loaded('suhosin') && $memory_limit < 256) {
3072
+ @ini_set('memory_limit', '256M');
 
 
 
 
 
 
 
 
 
3073
  }
3074
+ $fs = C_Fs::get_instance();
3075
+ // Uses the WordPress ZIP abstraction API
3076
+ include_once $fs->join_paths(ABSPATH, 'wp-admin', 'includes', 'file.php');
3077
+ WP_Filesystem(FALSE, get_temp_dir(), TRUE);
3078
+ // Ensure that we truly have the gallery id
3079
+ $gallery_id = $this->object->_get_gallery_id($gallery_id);
3080
+ $zipfile = $_FILES['file']['tmp_name'];
3081
+ $dest_path = implode(DIRECTORY_SEPARATOR, array(rtrim(get_temp_dir(), "/\\"), 'unpacked-' . M_I18n::mb_basename($zipfile)));
3082
+ // Attempt to extract the zip file into the normal system directory
3083
+ $extracted = $this->object->extract_zip($zipfile, $dest_path);
3084
+ // Now verify it worked. get_temp_dir() will check each of the following directories to ensure they are
3085
+ // a directory and against wp_is_writable(). Should ALL of those options fail we will fallback to wp_upload_dir().
3086
+ //
3087
+ // WP_TEMP_DIR
3088
+ // sys_get_temp_dir()
3089
+ // ini/upload_tmp_dir
3090
+ // WP_CONTENT_DIR
3091
+ // /tmp
3092
+ $size = 0;
3093
+ $files = glob($dest_path . DIRECTORY_SEPARATOR . '*');
3094
+ foreach ($files as $file) {
3095
+ if (is_array(stat($file))) {
3096
+ $size += filesize($file);
3097
+ }
3098
+ }
3099
+ // Extraction failed; attempt again with wp_upload_dir()
3100
+ if ($size == 0) {
3101
+ // Remove the empty directory we may have possibly created but could not write to
3102
+ $this->object->delete_directory($dest_path);
3103
+ $destination = wp_upload_dir();
3104
+ $destination_path = $destination['basedir'];
3105
+ $dest_path = implode(DIRECTORY_SEPARATOR, array(rtrim($destination_path, "/\\"), rand(), 'unpacked-' . M_I18n::mb_basename($zipfile)));
3106
+ $extracted = $this->object->extract_zip($zipfile, $dest_path);
3107
+ }
3108
+ if ($extracted) {
3109
+ $retval = $this->object->import_gallery_from_fs($dest_path, $gallery_id);
3110
+ }
3111
+ $this->object->delete_directory($dest_path);
3112
+ if (!extension_loaded('suhosin')) {
3113
+ @ini_set('memory_limit', $memory_limit . 'M');
3114
+ }
3115
+ return $retval;
3116
  }
3117
  /**
3118
+ * @param string $zipfile
3119
+ * @param string $dest_path
3120
+ * @return bool FALSE on failure
 
3121
  */
3122
+ public function extract_zip($zipfile, $dest_path)
3123
  {
3124
+ wp_mkdir_p($dest_path);
3125
+ if (class_exists('ZipArchive', FALSE) && apply_filters('unzip_file_use_ziparchive', TRUE)) {
3126
+ $zipObj = new ZipArchive();
3127
+ if ($zipObj->open($zipfile) === FALSE) {
3128
+ return FALSE;
3129
+ }
3130
+ for ($i = 0; $i < $zipObj->numFiles; $i++) {
3131
+ $filename = $zipObj->getNameIndex($i);
3132
+ if (!$this->object->is_allowed_image_extension($filename)) {
3133
+ continue;
3134
+ }
3135
+ $zipObj->extractTo($dest_path, array($zipObj->getNameIndex($i)));
3136
+ }
3137
  } else {
3138
+ require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
3139
+ $zipObj = new PclZip($zipfile);
3140
+ $zipContent = $zipObj->listContent();
3141
+ $indexesToExtract = array();
3142
+ foreach ($zipContent as $zipItem) {
3143
+ if ($zipItem['folder']) {
3144
+ continue;
3145
+ }
3146
+ if (!$this->object->is_allowed_image_extension($zipItem['stored_filename'])) {
3147
+ continue;
3148
+ }
3149
+ $indexesToExtract[] = $zipItem['index'];
3150
+ }
3151
+ if (!$zipObj->extractByIndex(implode(',', $indexesToExtract), $dest_path)) {
3152
+ return FALSE;
3153
+ }
3154
  }
3155
+ return TRUE;
3156
  }
3157
+ }
3158
+ /**
3159
+ * Model for NextGen Gallery Images
3160
+ * @mixin Mixin_NextGen_Gallery_Image_Validation
3161
+ * @implements I_Image
3162
+ */
3163
+ class C_Image extends C_DataMapper_Model
3164
+ {
3165
+ var $_mapper_interface = 'I_Image_Mapper';
3166
+ function define($properties = array(), $mapper = FALSE, $context = FALSE)
3167
+ {
3168
+ parent::define($mapper, $properties, $context);
3169
+ $this->add_mixin('Mixin_NextGen_Gallery_Image_Validation');
3170
+ $this->implement('I_Image');
3171
+ }
3172
+ /**
3173
+ * Instantiates a new model
3174
+ * @param array|stdClass $properties (optional)
3175
+ * @param C_Image_Mapper|false $mapper (optional)
3176
+ * @param string|false $context (optional)
3177
  */
3178
+ function initialize($properties = array(), $mapper = FALSE, $context = FALSE)
3179
  {
3180
+ if (!$mapper) {
3181
+ $mapper = $this->get_registry()->get_utility($this->_mapper_interface);
3182
  }
3183
+ parent::initialize($mapper, $properties);
3184
  }
3185
  /**
3186
+ * Returns the model representing the gallery associated with this image
3187
+ * @param object|false $model (optional)
3188
+ * @return C_Gallery|object
3189
  */
3190
+ function get_gallery($model = FALSE)
3191
  {
3192
+ return C_Gallery_Mapper::get_instance()->find($this->galleryid, $model);
 
 
 
 
 
 
 
 
3193
  }
3194
+ }
3195
+ class Mixin_NextGen_Gallery_Image_Validation extends Mixin
3196
+ {
3197
+ function validation()
 
 
 
 
3198
  {
3199
+ // Additional checks...
3200
+ if (isset($this->object->description)) {
3201
+ $this->object->description = M_NextGen_Data::strip_html($this->object->description, TRUE);
3202
  }
3203
+ if (isset($this->object->alttext)) {
3204
+ $this->object->alttext = M_NextGen_Data::strip_html($this->object->alttext, TRUE);
 
 
 
 
3205
  }
3206
+ $this->validates_presence_of('galleryid', 'filename', 'alttext', 'exclude', 'sortorder', 'imagedate');
3207
+ $this->validates_numericality_of('galleryid');
3208
+ $this->validates_numericality_of($this->id());
3209
+ $this->validates_numericality_of('sortorder');
3210
+ $this->validates_length_of('filename', 185, '<=', __('Image filenames may not be longer than 185 characters in length', 'nextgen-gallery'));
3211
+ return $this->object->is_valid();
3212
  }
3213
+ }
3214
+ /**
3215
+ * Class C_Image_Mapper
3216
+ *
3217
+ * @mixin Mixin_NextGen_Table_Extras
3218
+ * @mixin Mixin_Gallery_Image_Mapper
3219
+ * @implements I_Image_Mapper
3220
+ */
3221
+ class C_Image_Mapper extends C_CustomTable_DataMapper_Driver
3222
+ {
3223
+ public static $_instance = NULL;
3224
  /**
3225
+ * Defines the gallery image mapper
3226
+ * @param string|false $context (optional)
3227
+ * @param mixed $not_used
 
 
3228
  */
3229
+ function define($context = FALSE, $not_used = FALSE)
3230
  {
3231
+ // Add 'attachment' context
3232
+ if (!is_array($context)) {
3233
+ $context = array($context);
 
 
 
 
 
 
 
 
 
 
 
3234
  }
3235
+ array_push($context, 'attachment');
3236
+ // Define the mapper
3237
+ $this->_primary_key_column = 'pid';
3238
+ parent::define('ngg_pictures', $context);
3239
+ $this->add_mixin('Mixin_NextGen_Table_Extras');
3240
+ $this->add_mixin('Mixin_Gallery_Image_Mapper');
3241
+ $this->implement('I_Image_Mapper');
3242
+ $this->set_model_factory_method('image');
3243
+ // Define the columns
3244
+ $this->define_column('pid', 'BIGINT', 0);
3245
+ $this->define_column('image_slug', 'VARCHAR(255)');
3246
+ $this->define_column('post_id', 'BIGINT', 0);
3247
+ $this->define_column('galleryid', 'BIGINT', 0);
3248
+ $this->define_column('filename', 'VARCHAR(255)');
3249
+ $this->define_column('description', 'TEXT');
3250
+ $this->define_column('alttext', 'TEXT');
3251
+ $this->define_column('imagedate', 'DATETIME');
3252
+ $this->define_column('exclude', 'INT', 0);
3253
+ $this->define_column('sortorder', 'BIGINT', 0);
3254
+ $this->define_column('meta_data', 'TEXT');
3255
+ $this->define_column('extras_post_id', 'BIGINT', 0);
3256
+ $this->define_column('updated_at', 'BIGINT');
3257
+ // Mark the columns which should be unserialized
3258
+ $this->add_serialized_column('meta_data');
3259
+ }
3260
+ function initialize($object_name = FALSE)
3261
+ {
3262
+ parent::initialize('ngg_pictures');
3263
  }
3264
  /**
3265
+ * @param bool|string $context
3266
+ * @return C_Image_Mapper
 
3267
  */
3268
+ static function get_instance($context = False)
3269
  {
3270
+ if (is_null(self::$_instance)) {
3271
+ $klass = get_class();
3272
+ self::$_instance = new $klass($context);
 
 
 
 
 
 
 
3273
  }
3274
+ return self::$_instance;
 
 
 
 
3275
  }
3276
  /**
3277
+ * Finds all images for a gallery
3278
+ * @param $gallery
3279
+ * @param bool $model
3280
  *
3281
+ * @return array
3282
  */
3283
+ function find_all_for_gallery($gallery, $model = FALSE)
3284
  {
3285
+ $retval = array();
3286
+ $gallery_id = 0;
3287
+ if (is_object($gallery)) {
3288
+ if (isset($gallery->id_field)) {
3289
+ $gallery_id = $gallery->{$gallery->id_field};
3290
+ } else {
3291
+ $key = $this->object->get_primary_key_column();
3292
+ if (isset($gallery->{$key})) {
3293
+ $gallery_id = $gallery->{$key};
3294
+ }
3295
+ }
3296
+ } elseif (is_numeric($gallery)) {
3297
+ $gallery_id = $gallery;
3298
  }
3299
+ if ($gallery_id) {
3300
+ $retval = $this->object->select()->where(array("galleryid = %s", $gallery_id))->run_query(FALSE, $model);
 
 
 
3301
  }
3302
+ return $retval;
3303
+ }
3304
+ function reimport_metadata($image_or_id)
3305
+ {
3306
+ // Get the image
3307
+ $image = NULL;
3308
+ if (is_int($image_or_id)) {
3309
+ $image = $this->object->find($image_or_id);
3310
  } else {
3311
+ $image = $image_or_id;
3312
  }
3313
+ // Reset all image details that would have normally been imported
3314
+ if (is_array($image->meta_data)) {
3315
+ unset($image->meta_data['saved']);
3316
+ }
3317
+ nggAdmin::import_MetaData($image);
3318
+ return $this->object->save($image);
3319
  }
3320
  /**
3321
+ * Retrieves the id from an image
3322
+ * @param $image
3323
+ * @return bool
 
 
 
3324
  */
3325
+ function get_id($image)
3326
  {
3327
+ $retval = FALSE;
3328
+ // Have we been passed an entity and is the id_field set?
3329
+ if ($image instanceof stdClass) {
3330
+ if (isset($image->id_field)) {
3331
+ $retval = $image->{$image->id_field};
3332
+ }
3333
+ } else {
3334
+ $retval = $image->id();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3335
  }
3336
+ // If we still don't have an id, then we'll lookup the primary key
3337
+ // and try fetching it manually
3338
+ if (!$retval) {
3339
+ $key = $this->object->get_primary_key_column();
3340
+ $retval = $image->{$key};
3341
  }
3342
+ return $retval;
3343
+ }
3344
+ }
3345
+ /**
3346
+ * Sets the alttext property as the post title
3347
+ */
3348
+ class Mixin_Gallery_Image_Mapper extends Mixin
3349
+ {
3350
+ function destroy($image)
3351
+ {
3352
+ $retval = $this->call_parent('destroy', $image);
3353
+ // Delete tag associations with the image
3354
+ if (!is_numeric($image)) {
3355
+ $image = $image->{$image->id_field};
3356
  }
3357
+ wp_delete_object_term_relationships($image, 'ngg_tag');
3358
+ C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
3359
+ return $retval;
 
 
 
3360
  }
3361
+ function _save_entity($entity)
 
 
 
 
 
 
3362
  {
3363
+ $entity->updated_at = time();
3364
+ // If successfully saved then import metadata
3365
+ $retval = $this->call_parent('_save_entity', $entity);
3366
+ if ($retval) {
3367
+ include_once NGGALLERY_ABSPATH . '/admin/functions.php';
3368
+ $image_id = $this->get_id($entity);
3369
+ if (!isset($entity->meta_data['saved'])) {
3370
+ nggAdmin::import_MetaData($image_id);
3371
+ }
3372
+ C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3373
  }
3374
+ return $retval;
3375
  }
3376
+ function get_post_title($entity)
 
 
 
 
 
 
 
3377
  {
3378
+ return $entity->alttext;
3379
+ }
3380
+ function set_defaults($entity)
3381
+ {
3382
+ // If not set already, we'll add an exclude property. This is used
3383
+ // by NextGEN Gallery itself, as well as the Attach to Post module
3384
+ $this->object->_set_default_value($entity, 'exclude', 0);
3385
+ // Ensure that the object has a description attribute
3386
+ $this->object->_set_default_value($entity, 'description', '');
3387
+ // If not set already, set a default sortorder
3388
+ $this->object->_set_default_value($entity, 'sortorder', 0);
3389
+ // The imagedate must be set
3390
+ if (!isset($entity->imagedate) or is_null($entity->imagedate) or $entity->imagedate == '0000-00-00 00:00:00') {
3391
+ $entity->imagedate = date("Y-m-d H:i:s");
3392
  }
3393
+ // If a filename is set, and no alttext is set, then set the alttext
3394
+ // to the basename of the filename (legacy behavior)
3395
+ if (isset($entity->filename)) {
3396
+ $path_parts = M_I18n::mb_pathinfo($entity->filename);
3397
+ $alttext = !isset($path_parts['filename']) ? substr($path_parts['basename'], 0, strpos($path_parts['basename'], '.')) : $path_parts['filename'];
3398
+ $this->object->_set_default_value($entity, 'alttext', $alttext);
3399
+ }
3400
+ // Set unique slug
3401
+ if (isset($entity->alttext) && empty($entity->image_slug)) {
3402
+ $entity->image_slug = nggdb::get_unique_slug(sanitize_title_with_dashes($entity->alttext), 'image');
3403
+ }
3404
+ // Ensure that the exclude parameter is an integer or boolean-evaluated
3405
+ // value
3406
+ if (is_string($entity->exclude)) {
3407
+ $entity->exclude = intval($entity->exclude);
3408
+ }
3409
+ // Trim alttext and description
3410
+ $entity->description = trim($entity->description);
3411
+ $entity->alttext = trim($entity->alttext);
3412
+ if (!is_admin()) {
3413
+ if (!empty($entity->description)) {
3414
+ $entity->description = M_I18N::translate($entity->description, 'pic_' . $entity->{$entity->id_field} . '_description');
3415
+ }
3416
+ if (!empty($entity->alttext)) {
3417
+ $entity->alttext = M_I18N::translate($entity->alttext, 'pic_' . $entity->{$entity->id_field} . '_alttext');
3418
+ }
3419
  }
 
3420
  }
3421
+ }
3422
+ /**
3423
+ * This class provides a lazy-loading wrapper to the NextGen-Legacy "nggImage" class for use in legacy style templates
3424
+ */
3425
+ class C_Image_Wrapper
3426
+ {
3427
+ public $_cache;
3428
+ // cache of retrieved values
3429
+ public $_settings;
3430
+ // I_Settings_Manager cache
3431
+ public $_storage;
3432
+ // I_Gallery_Storage cache
3433
+ public $_galleries;
3434
+ // cache of I_Gallery_Mapper (plural)
3435
+ public $_orig_image;
3436
+ // original provided image
3437
+ public $_orig_image_id;
3438
+ // original image ID
3439
+ public $_cache_overrides;
3440
+ // allow for forcing variable values
3441
+ public $_legacy = FALSE;
3442
+ public $_displayed_gallery;
3443
+ // cached object
3444
  /**
3445
+ * Constructor. Converts the image class into an array and fills from defaults any missing values
3446
  *
3447
+ * @param object $image Individual result from displayed_gallery->get_entities()
3448
+ * @param object $displayed_gallery Displayed gallery -- MAY BE NULL
3449
+ * @param bool $legacy Whether the image source is from NextGen Legacy or NextGen
3450
+ * @return void
 
3451
  */
3452
+ public function __construct($image, $displayed_gallery = NULL, $legacy = FALSE)
3453
  {
3454
+ // for clarity
3455
+ if ($displayed_gallery && isset($displayed_gallery->display_settings['number_of_columns'])) {
3456
+ $columns = $displayed_gallery->display_settings['number_of_columns'];
3457
+ } else {
3458
+ $columns = 0;
 
 
 
 
 
 
 
 
 
 
 
3459
  }
3460
+ // Public variables
3461
+ $defaults = array(
3462
+ 'errmsg' => '',
3463
+ // Error message to display, if any
3464
+ 'error' => FALSE,
3465
+ // Error state
3466
+ 'imageURL' => '',
3467
+ // URL Path to the image
3468
+ 'thumbURL' => '',
3469
+ // URL Path to the thumbnail
3470
+ 'imagePath' => '',
3471
+ // Server Path to the image
3472
+ 'thumbPath' => '',
3473
+ // Server Path to the thumbnail
3474
+ 'href' => '',
3475
+ // A href link code
3476
+ // Mostly constant
3477
+ 'thumbPrefix' => 'thumbs_',
3478
+ // FolderPrefix to the thumbnail
3479
+ 'thumbFolder' => '/thumbs/',
3480
+ // Foldername to the thumbnail
3481
+ // Image Data
3482
+ 'galleryid' => 0,
3483
+ // Gallery ID
3484
+ 'pid' => 0,
3485
+ // Image ID
3486
+ 'filename' => '',
3487
+ // Image filename
3488
+ 'description' => '',
3489
+ // Image description
3490
+ 'alttext' => '',
3491
+ // Image alttext
3492
+ 'imagedate' => '',
3493
+ // Image date/time
3494
+ 'exclude' => '',
3495
+ // Image exclude
3496
+ 'thumbcode' => '',
3497
+ // Image effect code
3498
+ // Gallery Data
3499
+ 'name' => '',
3500
+ // Gallery name
3501
+ 'path' => '',
3502
+ // Gallery path
3503
+ 'title' => '',
3504
+ // Gallery title
3505
+ 'pageid' => 0,
3506
+ // Gallery page ID
3507
+ 'previewpic' => 0,
3508
+ // Gallery preview pic
3509
+ 'style' => $columns > 0 ? 'style="width:' . floor(100 / $columns) . '%;"' : '',
3510
+ 'hidden' => FALSE,
3511
+ 'permalink' => '',
3512
+ 'tags' => '',
3513
+ );
3514
+ // convert the image to an array and apply the defaults
3515
+ $this->_orig_image = $image;
3516
+ $image = (array) $image;
3517
+ foreach ($defaults as $key => $val) {
3518
+ if (!isset($image[$key])) {
3519
+ $image[$key] = $val;
3520
+ }
3521
  }
3522
+ // cache the results
3523
+ ksort($image);
3524
+ $id_field = !empty($image['id_field']) ? $image['id_field'] : 'pid';
3525
+ $this->_cache = (array) apply_filters('ngg_image_object', (object) $image, $image[$id_field]);
3526
+ $this->_orig_image_id = $image[$id_field];
3527
+ $this->_legacy = $legacy;
3528
+ $this->_displayed_gallery = $displayed_gallery;
3529
  }
3530
+ public function __set($name, $value)
 
 
 
 
 
 
 
3531
  {
3532
+ $this->_cache[$name] = $value;
 
 
 
 
 
 
 
 
3533
  }
3534
+ public function __isset($name)
 
 
 
 
 
 
3535
  {
3536
+ return isset($this->_cache[$name]);
3537
+ }
3538
+ public function __unset($name)
3539
+ {
3540
+ unset($this->_cache[$name]);
3541
  }
3542
  /**
3543
+ * Lazy-loader for image variables.
3544
  *
3545
+ * @param string $name Parameter name
3546
+ * @return mixed
3547
  */
3548
+ public function __get($name)
3549
  {
3550
+ if (isset($this->_cache_overrides[$name])) {
3551
+ return $this->_cache_overrides[$name];
 
 
 
 
 
 
3552
  }
3553
+ // at the bottom we default to returning $this->_cache[$name].
3554
+ switch ($name) {
3555
+ case 'alttext':
3556
+ $this->_cache['alttext'] = empty($this->_cache['alttext']) ? ' ' : html_entity_decode(stripslashes($this->_cache['alttext']));
3557
+ return $this->_cache['alttext'];
3558
+ case 'author':
3559
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3560
+ $this->_cache['author'] = $gallery->name;
3561
+ return $this->_cache['author'];
3562
+ case 'caption':
3563
+ $caption = html_entity_decode(stripslashes($this->__get('description')));
3564
+ if (empty($caption)) {
3565
+ $caption = '&nbsp;';
3566
+ }
3567
+ $this->_cache['caption'] = $caption;
3568
+ return $this->_cache['caption'];
3569
+ case 'description':
3570
+ $this->_cache['description'] = empty($this->_cache['description']) ? ' ' : html_entity_decode(stripslashes($this->_cache['description']));
3571
+ return $this->_cache['description'];
3572
+ case 'galdesc':
3573
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3574
+ $this->_cache['galdesc'] = $gallery->name;
3575
+ return $this->_cache['galdesc'];
3576
+ case 'gid':
3577
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3578
+ $this->_cache['gid'] = $gallery->{$gallery->id_field};
3579
+ return $this->_cache['gid'];
3580
+ case 'href':
3581
+ return $this->__get('imageHTML');
3582
+ case 'id':
3583
+ return $this->_orig_image_id;
3584
+ case 'imageHTML':
3585
+ $tmp = '<a href="' . $this->__get('imageURL') . '" title="' . htmlspecialchars(stripslashes($this->__get('description'))) . '" ' . $this->get_thumbcode($this->__get('name')) . '>' . '<img alt="' . $this->__get('alttext') . '" src="' . $this->__get('imageURL') . '"/>' . '</a>';
3586
+ $this->_cache['href'] = $tmp;
3587
+ $this->_cache['imageHTML'] = $tmp;
3588
+ return $this->_cache['imageHTML'];
3589
+ case 'imagePath':
3590
+ $storage = $this->get_storage();
3591
+ $this->_cache['imagePath'] = $storage->get_image_abspath($this->_orig_image, 'full');
3592
+ return $this->_cache['imagePath'];
3593
+ case 'imageURL':
3594
+ $storage = $this->get_storage();
3595
+ $this->_cache['imageURL'] = $storage->get_image_url($this->_orig_image, 'full');
3596
+ return $this->_cache['imageURL'];
3597
+ case 'linktitle':
3598
+ $this->_cache['linktitle'] = htmlspecialchars(stripslashes($this->__get('description')));
3599
+ return $this->_cache['linktitle'];
3600
+ case 'name':
3601
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3602
+ $this->_cache['name'] = $gallery->name;
3603
+ return $this->_cache['name'];
3604
+ case 'pageid':
3605
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3606
+ $this->_cache['pageid'] = $gallery->name;
3607
+ return $this->_cache['pageid'];
3608
+ case 'path':
3609
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3610
+ $this->_cache['path'] = $gallery->name;
3611
+ return $this->_cache['path'];
3612
+ case 'permalink':
3613
+ $this->_cache['permalink'] = $this->__get('imageURL');
3614
+ return $this->_cache['permalink'];
3615
+ case 'pid':
3616
+ return $this->_orig_image_id;
3617
+ case 'id_field':
3618
+ $this->_cache['id_field'] = !empty($this->_orig_image->id_field) ? $this->_orig_image->id_field : 'pid';
3619
+ return $this->_cache['id_field'];
3620
+ case 'pidlink':
3621
+ $application = C_Router::get_instance()->get_routed_app();
3622
+ $controller = C_Display_Type_Controller::get_instance();
3623
+ $this->_cache['pidlink'] = $controller->set_param_for($application->get_routed_url(TRUE), 'pid', $this->__get('image_slug'));
3624
+ return $this->_cache['pidlink'];
3625
+ case 'previewpic':
3626
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3627
+ $this->_cache['previewpic'] = $gallery->name;
3628
+ return $this->_cache['previewpic'];
3629
+ case 'size':
3630
+ $w = 0;
3631
+ $h = 0;
3632
+ if ($this->_displayed_gallery && isset($this->_displayed_gallery->display_settings)) {
3633
+ $ds = $this->_displayed_gallery->display_settings;
3634
+ if (isset($ds['override_thumbnail_settings']) && $ds['override_thumbnail_settings']) {
3635
+ $w = $ds['thumbnail_width'];
3636
+ $h = $ds['thumbnail_height'];
3637
  }
3638
  }
3639
+ if (!$w || !$h) {
3640
+ if (is_string($this->_orig_image->meta_data)) {
3641
+ $this->_orig_image = C_NextGen_Serializable::unserialize($this->_orig_image->meta_data);
3642
+ }
3643
+ if (!isset($this->_orig_image->meta_data['thumbnail'])) {
3644
+ $storage = $this->get_storage();
3645
+ $storage->generate_thumbnail($this->_orig_image);
3646
+ }
3647
+ $w = $this->_orig_image->meta_data['thumbnail']['width'];
3648
+ $h = $this->_orig_image->meta_data['thumbnail']['height'];
3649
+ }
3650
+ return "width='{$w}' height='{$h}'";
3651
+ case 'slug':
3652
+ $gallery = $this->get_legacy_gallery($this->__get('galleryid'));
3653
+ $this->_cache['slug'] = $gallery->name;
3654
+ return $this->_cache['slug'];
3655
+ case 'tags':
3656
+ $this->_cache['tags'] = wp_get_object_terms($this->__get('id'), 'ngg_tag', 'fields=all');
3657
+ return $this->_cache['tags'];
3658
+ case 'thumbHTML':
3659
+ $tmp = '<a href="' . $this->__get('imageURL') . '" title="' . htmlspecialchars(stripslashes($this->__get('description'))) . '" ' . $this->get_thumbcode($this->__get('name')) . '>' . '<img alt="' . $this->__get('alttext') . '" src="' . $this->thumbURL . '"/>' . '</a>';
3660
+ $this->_cache['href'] = $tmp;
3661
+ $this->_cache['thumbHTML'] = $tmp;
3662
+ return $this->_cache['thumbHTML'];
3663
+ case 'thumbPath':
3664
+ $storage = $this->get_storage();
3665
+ $this->_cache['thumbPath'] = $storage->get_image_abspath($this->_orig_image, 'thumbnail');
3666
+ return $this->_cache['thumbPath'];
3667
+ case 'thumbnailURL':
3668
+ $storage = $this->get_storage();
3669
+ $thumbnail_size_name = 'thumbnail';
3670
+ if ($this->_displayed_gallery && isset($this->_displayed_gallery->display_settings)) {
3671
+ $ds = $this->_displayed_gallery->display_settings;
3672
+ if (isset($ds['override_thumbnail_settings']) && $ds['override_thumbnail_settings']) {
3673
+ $dynthumbs = C_Component_Registry::get_instance()->get_utility('I_Dynamic_Thumbnails_Manager');
3674
+ $dyn_params = array('width' => $ds['thumbnail_width'], 'height' => $ds['thumbnail_height']);
3675
+ if ($ds['thumbnail_quality']) {
3676
+ $dyn_params['quality'] = $ds['thumbnail_quality'];
3677
+ }
3678
+ if ($ds['thumbnail_crop']) {
3679
+ $dyn_params['crop'] = TRUE;
3680
+ }
3681
+ if ($ds['thumbnail_watermark']) {
3682
+ $dyn_params['watermark'] = TRUE;
3683
  }
3684
+ $thumbnail_size_name = $dynthumbs->get_size_name($dyn_params);
3685
  }
3686
  }
3687
+ $this->_cache['thumbnailURL'] = $storage->get_image_url($this->_orig_image, $thumbnail_size_name);
3688
+ return $this->_cache['thumbnailURL'];
3689
+ case 'thumbcode':
3690
+ if ($this->_displayed_gallery && isset($this->_displayed_gallery->display_settings) && isset($this->_displayed_gallery->display_settings['use_imagebrowser_effect']) && $this->_displayed_gallery->display_settings['use_imagebrowser_effect'] && !empty($this->_orig_image->thumbcode)) {
3691
+ $this->_cache['thumbcode'] = $this->_orig_image->thumbcode;
3692
+ } else {
3693
+ $this->_cache['thumbcode'] = $this->get_thumbcode($this->__get('name'));
3694
+ }
3695
+ return $this->_cache['thumbcode'];
3696
+ case 'thumbURL':
3697
+ return $this->__get('thumbnailURL');
3698
+ case 'title':
3699
+ $this->_cache['title'] = stripslashes($this->__get('name'));
3700
+ return $this->_cache['title'];
3701
+ case 'url':
3702
+ $storage = $this->get_storage();
3703
+ $this->_cache['url'] = $storage->get_image_url($this->_orig_image, 'full');
3704
+ return $this->_cache['url'];
3705
  default:
3706
+ return $this->_cache[$name];
3707
  }
3708
+ }
3709
+ // called on initial nggLegacy image at construction. not sure what to do with it now.
3710
+ function construct_ngg_Image($gallery)
3711
+ {
3712
+ do_action_ref_array('ngg_get_image', array(&$this));
3713
+ unset($this->tags);
3714
+ }
3715
+ /**
3716
+ * Retrieves and caches an I_Settings_Manager instance
3717
+ *
3718
+ * @return mixed
3719
+ */
3720
+ function get_settings()
3721
+ {
3722
+ if (is_null($this->_settings)) {
3723
+ $this->_settings = C_NextGen_Settings::get_instance();
3724
+ }
3725
+ return $this->_settings;
3726
  }
3727
  /**
3728
+ * Retrieves and caches an I_Gallery_Storage instance
3729
+ *
3730
+ * @return mixed
3731
  */
3732
+ function get_storage()
3733
  {
3734
+ if (is_null($this->_storage)) {
3735
+ $this->_storage = C_Gallery_Storage::get_instance();
 
 
 
 
3736
  }
3737
+ return $this->_storage;
3738
  }
3739
  /**
3740
+ * Retrieves I_Gallery_Mapper instance.
3741
  *
3742
+ * @param int $gallery_id Gallery ID
3743
+ * @return mixed
 
3744
  */
3745
+ function get_gallery($gallery_id)
3746
  {
3747
+ if (isset($this->container) && method_exists($this->container, 'get_gallery')) {
3748
+ return $this->container->get_gallery($gallery_id);
 
 
 
 
 
3749
  }
3750
+ return C_Gallery_Mapper::get_instance()->find($gallery_id);
 
 
 
 
 
 
 
3751
  }
3752
  /**
3753
+ * Retrieves I_Gallery_Mapper instance.
 
3754
  *
3755
+ * @param int $gallery_id Gallery ID
3756
+ * @return mixed
 
 
3757
  */
3758
+ function get_legacy_gallery($gallery_id)
3759
  {
3760
+ return C_Gallery_Mapper::get_instance()->find($gallery_id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3761
  }
3762
  /**
3763
+ * Get the thumbnail code (to add effects on thumbnail click)
3764
  *
3765
+ * Applies the filter 'ngg_get_thumbcode'
3766
+ * @param string $gallery_name (optional) Default = ''
3767
+ * @return string
 
3768
  */
3769
+ function get_thumbcode($gallery_name = '')
3770
  {
3771
+ if (empty($this->_displayed_gallery)) {
3772
+ $effect_code = C_NextGen_Settings::get_instance()->thumbCode;
3773
+ $effect_code = str_replace('%GALLERY_ID%', $gallery_name, $effect_code);
3774
+ $effect_code = str_replace('%GALLERY_NAME%', $gallery_name, $effect_code);
3775
+ $retval = $effect_code;
3776
+ } else {
3777
+ $controller = C_Display_Type_Controller::get_instance();
3778
+ $retval = $controller->get_effect_code($this->_displayed_gallery);
3779
+ // This setting requires that we disable the effect code
3780
+ $ds = $this->_displayed_gallery->display_settings;
3781
+ if (isset($ds['use_imagebrowser_effect']) && $ds['use_imagebrowser_effect']) {
3782
+ $retval = '';
3783
+ }
3784
  }
3785
+ $retval = apply_filters('ngg_get_thumbcode', $retval, $this);
3786
+ // ensure some additional data- fields are added; provides Pro-Lightbox compatibility
3787
+ $retval .= ' data-image-id="' . $this->__get('id') . '"';
3788
+ $retval .= ' data-src="' . $this->__get('imageURL') . '"';
3789
+ $retval .= ' data-thumbnail="' . $this->__get('thumbnailURL') . '"';
3790
+ $retval .= ' data-title="' . esc_attr($this->__get('alttext')) . '"';
3791
+ $retval .= ' data-description="' . esc_attr($this->__get('description')) . '"';
3792
+ $this->_cache['thumbcode'] = $retval;
3793
+ return $retval;
3794
  }
3795
  /**
3796
+ * For compatibility support
3797
  *
3798
+ * @return mixed
 
 
 
 
 
3799
  */
3800
+ function get_href_link()
3801
  {
3802
+ return $this->__get('imageHTML');
 
 
 
 
 
3803
  }
3804
+ /**
3805
+ * For compatibility support
3806
+ *
3807
+ * @return mixed
3808
+ */
3809
+ function get_href_thumb_link()
3810
  {
3811
+ return $this->__get('thumbHTML');
 
 
3812
  }
3813
  /**
3814
+ * Function exists for legacy support but has been gutted to not do anything
 
3815
  *
3816
+ * @param string|int $width (optional) Default = ''
3817
+ * @param string|int $height (optional) Default = ''
3818
+ * @param string $mode could be watermark | web20 | crop
3819
+ * @return bool|string The url for the image or false if failed
3820
  */
3821
+ function cached_singlepic_file($width = '', $height = '', $mode = '')
3822
  {
3823
+ $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
3824
+ $storage = $this->get_storage();
3825
+ // determine what to do with 'mode'
3826
+ $display_reflection = FALSE;
3827
+ $display_watermark = FALSE;
3828
+ if (!is_array($mode)) {
3829
+ $mode = explode(',', $mode);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3830
  }
3831
+ if (in_array('web20', $mode)) {
3832
+ $display_reflection = TRUE;
3833
+ }
3834
+ if (in_array('watermark', $mode)) {
3835
+ $display_watermark = TRUE;
3836
+ }
3837
+ // and go for it
3838
+ $params = array('width' => $width, 'height' => $height, 'watermark' => $display_watermark, 'reflection' => $display_reflection);
3839
+ return $storage->get_image_url((object) $this->_cache, $dynthumbs->get_size_name($params));
3840
  }
3841
  /**
3842
+ * Get the tags associated to this image
3843
  */
3844
+ function get_tags()
3845
  {
3846
+ return $this->__get('tags');
 
 
 
3847
  }
3848
  /**
3849
+ * Get the permalink to the image
3850
+ *
3851
+ * TODO: Get a permalink to a page presenting the image
 
 
 
 
 
 
 
 
 
 
 
 
3852
  */
3853
+ function get_permalink()
3854
  {
3855
+ return $this->__get('permalink');
 
 
 
 
 
 
 
 
3856
  }
 
 
 
 
 
 
 
 
3857
  /**
3858
+ * Returns the _cache array; used by nggImage
3859
+ * @return array
 
 
3860
  */
3861
+ function _get_image()
3862
  {
3863
+ return $this->_cache;
 
 
 
 
 
 
 
 
 
3864
  }
3865
+ }
3866
+ class C_Image_Wrapper_Collection implements ArrayAccess
3867
+ {
3868
+ public $container = array();
3869
+ public $galleries = array();
3870
+ public function offsetExists($offset)
3871
  {
3872
+ return isset($this->container[$offset]);
3873
+ }
3874
+ public function offsetGet($offset)
3875
+ {
3876
+ return isset($this->container[$offset]) ? $this->container[$offset] : null;
3877
+ }
3878
+ public function offsetSet($offset, $value)
3879
+ {
3880
+ if (is_object($value)) {
3881
+ $value->container = $this;
3882
  }
3883
+ if (is_null($offset)) {
3884
+ $this->container[] = $value;
3885
+ } else {
3886
+ $this->container[$offset] = $value;
 
 
 
 
 
 
 
 
 
 
 
3887
  }
3888
+ }
3889
+ public function offsetUnset($offset)
3890
+ {
3891
+ unset($this->container[$offset]);
3892
  }
3893
  /**
3894
+ * Retrieves and caches an I_Gallery_Mapper instance for this gallery id
3895
  *
3896
+ * @param int $gallery_id Gallery ID
3897
+ * @return mixed
 
 
3898
  */
3899
+ public function get_gallery($gallery_id)
3900
  {
3901
+ if (!isset($this->galleries[$gallery_id]) || is_null($this->galleries[$gallery_id])) {
3902
+ $this->galleries[$gallery_id] = C_Gallery_Mapper::get_instance();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3903
  }
3904
+ return $this->galleries[$gallery_id];
3905
  }
3906
+ }
3907
+ class C_NextGen_Data_Installer extends C_NggLegacy_Installer
3908
+ {
3909
+ function get_registry()
3910
  {
3911
+ return C_Component_Registry::get_instance();
 
 
3912
  }
3913
+ function install()
 
 
 
 
3914
  {
3915
+ $this->remove_table_extra_options();
3916
+ }
3917
+ function remove_table_extra_options()
3918
+ {
3919
+ global $wpdb;
3920
+ $likes = array("option_name LIKE '%ngg_gallery%'", "option_name LIKE '%ngg_pictures%'", "option_name LIKE '%ngg_album%'");
3921
+ $sql = "DELETE FROM {$wpdb->options} WHERE " . implode(" OR ", $likes);
3922
+ $wpdb->query($sql);
3923
+ }
3924
+ function uninstall($hard = FALSE)
3925
+ {
3926
+ if ($hard) {
3927
+ /* Yes: this is commented twice.
3928
+ // TODO for now never delete galleries/albums/content
3929
+ # $mappers = array(
3930
+ # $this->get_registry()->get_utility('I_Album_Mapper'),
3931
+ # $this->get_registry()->get_utility('I_Gallery_Mapper'),
3932
+ # $this->get_registry()->get_utility('I_Image_Mapper'),
3933
+ # );
3934
+
3935
+ # foreach ($mappers as $mapper) {
3936
+ # $mapper->delete()->run_query();
3937
+ # }
3938
+
3939
+ # // Remove ngg tags
3940
+ # global $wpdb;
3941
+ # $wpdb->query("DELETE FROM {$wpdb->terms} WHERE term_id IN (SELECT term_id FROM {$wpdb->term_taxonomy} WHERE taxonomy='ngg_tag')");
3942
+ # $wpdb->query("DELETE FROM {$wpdb->term_taxonomy} WHERE taxonomy='ngg_tag'");
3943
+ */
3944
+ }
3945
  }
3946
+ }
3947
+ class C_NextGen_Metadata extends C_Component
3948
+ {
3949
+ // Image data
3950
+ public $image = '';
3951
+ // The image object
3952
+ public $file_path = '';
3953
+ // Path to the image file
3954
+ public $size = FALSE;
3955
+ // The image size
3956
+ public $exif_data = FALSE;
3957
+ // EXIF data array
3958
+ public $iptc_data = FALSE;
3959
+ // IPTC data array
3960
+ public $xmp_data = FALSE;
3961
+ // XMP data array
3962
+ // Filtered Data
3963
+ public $exif_array = FALSE;
3964
+ // EXIF data array
3965
+ public $iptc_array = FALSE;
3966
+ // IPTC data array
3967
+ public $xmp_array = FALSE;
3968
+ // XMP data array
3969
+ public $sanitize = FALSE;
3970
+ // sanitize meta data on request
3971
  /**
3972
+ * Class constructor
3973
+ *
3974
+ * @param int $image Image ID
3975
+ * @param bool $onlyEXIF TRUE = will parse only EXIF data
3976
+ * @return bool FALSE if the file does not exist or metadat could not be read
 
 
 
 
 
 
 
3977
  */
3978
+ public function __construct($image, $onlyEXIF = FALSE)
3979
  {
3980
+ if (is_numeric($image)) {
3981
+ $image = C_Image_Mapper::get_instance()->find($image);
3982
+ }
3983
+ $this->image = apply_filters('ngg_find_image_meta', $image);
3984
+ $this->file_path = C_Gallery_Storage::get_instance()->get_image_abspath($this->image);
3985
+ if (!@file_exists($this->file_path)) {
3986
+ return FALSE;
3987
+ }
3988
+ $this->size = @getimagesize($this->file_path, $metadata);
3989
+ if ($this->size && is_array($metadata)) {
3990
+ // get exif - data
3991
+ if (is_callable('exif_read_data')) {
3992
+ $this->exif_data = @exif_read_data($this->file_path, NULL, TRUE);
3993
+ }
3994
+ // stop here if we didn't need other meta data
3995
+ if ($onlyEXIF) {
3996
+ return TRUE;
3997
+ }
3998
+ // get the iptc data - should be in APP13
3999
+ if (is_callable('iptcparse') && isset($metadata['APP13'])) {
4000
+ $this->iptc_data = @iptcparse($metadata['APP13']);
4001
+ }
4002
+ // get the xmp data in a XML format
4003
+ if (is_callable('xml_parser_create')) {
4004
+ $this->xmp_data = $this->extract_XMP($this->file_path);
4005
+ }
4006
+ return TRUE;
4007
+ }
4008
+ return FALSE;
4009
  }
 
 
 
 
 
 
 
4010
  /**
4011
+ * return the saved meta data from the database
4012
+ *
4013
+ * @since 1.4.0
4014
+ * @param string $object (optional)
4015
+ * @return array|mixed return either the complete array or the single object
 
4016
  */
4017
+ function get_saved_meta($object = false)
4018
  {
4019
+ $meta = $this->image->meta_data;
4020
+ // Check if we already import the meta data to the database
4021
+ if (!is_array($meta) || !isset($meta['saved']) || $meta['saved'] !== TRUE) {
4022
+ return false;
4023
  }
4024
+ // return one element if requested
4025
+ if ($object) {
4026
+ return $meta[$object];
 
 
 
 
4027
  }
4028
+ //removed saved parameter we don't need that to show
4029
+ unset($meta['saved']);
4030
+ // and remove empty tags or arrays
4031
+ foreach ($meta as $key => $value) {
4032
+ if (empty($value) or is_array($value)) {
4033
+ unset($meta[$key]);
4034
+ }
4035
+ }
4036
+ // on request sanitize the output
4037
+ if ($this->sanitize == true) {
4038
+ array_walk($meta, 'esc_html');
4039
+ }
4040
+ return $meta;
4041
  }
4042
  /**
4043
+ * nggMeta::get_EXIF()
4044
+ * See also http://trac.wordpress.org/changeset/6313
4045
+ *
4046
+ * @return bool|array
 
4047
  */
4048
+ function get_EXIF($object = false)
4049
  {
4050
+ if (!$this->exif_data) {
4051
+ return false;
4052
+ }
4053
+ if (!is_array($this->exif_array)) {
4054
+ $meta = array();
4055
+ if (isset($this->exif_data['EXIF'])) {
4056
+ $exif = $this->exif_data['EXIF'];
4057
+ if (!empty($exif['FNumber'])) {
4058
+ $meta['aperture'] = 'F ' . round($this->exif_frac2dec($exif['FNumber']), 2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4059
  }
4060
+ if (!empty($exif['Model'])) {
4061
+ $meta['camera'] = trim($exif['Model']);
 
 
 
 
 
 
 
 
 
 
 
 
 
4062
  }
4063
+ if (!empty($exif['DateTimeDigitized'])) {
4064
+ $meta['created_timestamp'] = $this->exif_date2ts($exif['DateTimeDigitized']);
4065
+ } else {
4066
+ if (!empty($exif['DateTimeOriginal'])) {
4067
+ $meta['created_timestamp'] = $this->exif_date2ts($exif['DateTimeOriginal']);
 
 
 
 
 
 
 
 
 
4068
  } else {
4069
+ if (!empty($exif['FileDateTime'])) {
4070
+ $meta['created_timestamp'] = $this->exif_date2ts($exif['FileDateTime']);
4071
+ }
4072
  }
4073
  }
4074
+ if (!empty($exif['FocalLength'])) {
4075
+ $meta['focal_length'] = $this->exif_frac2dec($exif['FocalLength']) . __(' mm', 'nggallery');
4076
+ }
4077
+ if (!empty($exif['ISOSpeedRatings'])) {
4078
+ $meta['iso'] = $exif['ISOSpeedRatings'];
4079
+ }
4080
+ if (!empty($exif['ExposureTime'])) {
4081
+ $meta['shutter_speed'] = $this->exif_frac2dec($exif['ExposureTime']);
4082
+ $meta['shutter_speed'] = ($meta['shutter_speed'] > 0.0 and $meta['shutter_speed'] < 1.0) ? '1/' . round(1 / $meta['shutter_speed'], -1) : $meta['shutter_speed'];
4083
+ $meta['shutter_speed'] .= __(' sec', 'nggallery');
4084
+ }
4085
+ //Bit 0 indicates the flash firing status
4086
+ if (!empty($exif['Flash'])) {
4087
+ $meta['flash'] = $exif['Flash'] & 1 ? __('Fired', 'nggallery') : __('Not fired', ' nggallery');
4088
+ }
4089
  }
4090
+ // additional information
4091
+ if (isset($this->exif_data['IFD0'])) {
4092
+ $exif = $this->exif_data['IFD0'];
4093
+ if (!empty($exif['Model'])) {
4094
+ $meta['camera'] = $exif['Model'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4095
  }
4096
+ if (!empty($exif['Make'])) {
4097
+ $meta['make'] = $exif['Make'];
 
 
 
 
 
 
4098
  }
4099
+ if (!empty($exif['ImageDescription'])) {
4100
+ $meta['title'] = $this->utf8_encode($exif['ImageDescription']);
 
 
4101
  }
4102
+ if (!empty($exif['Orientation'])) {
4103
+ $meta['Orientation'] = $exif['Orientation'];
 
 
 
 
 
 
 
 
 
 
4104
  }
4105
+ }
4106
+ // this is done by Windows
4107
+ if (isset($this->exif_data['WINXP'])) {
4108
+ $exif = $this->exif_data['WINXP'];
4109
+ if (!empty($exif['Title']) && empty($meta['title'])) {
4110
+ $meta['title'] = $this->utf8_encode($exif['Title']);
 
 
 
 
4111
  }
4112
+ if (!empty($exif['Author'])) {
4113
+ $meta['author'] = $this->utf8_encode($exif['Author']);
 
 
 
4114
  }
4115
+ if (!empty($exif['Keywords'])) {
4116
+ $meta['keywords'] = $this->utf8_encode($exif['Keywords']);
 
 
 
4117
  }
4118
+ if (!empty($exif['Subject'])) {
4119
+ $meta['subject'] = $this->utf8_encode($exif['Subject']);
4120
  }
4121
+ if (!empty($exif['Comments'])) {
4122
+ $meta['caption'] = $this->utf8_encode($exif['Comments']);
 
4123
  }
 
 
 
 
 
 
 
4124
  }
4125
+ $this->exif_array = $meta;
4126
  }
4127
+ // return one element if requested
4128
+ if ($object == true) {
4129
+ $value = isset($this->exif_array[$object]) ? $this->exif_array[$object] : false;
4130
+ return $value;
4131
+ }
4132
+ // on request sanitize the output
4133
+ if ($this->sanitize == true) {
4134
+ array_walk($this->exif_array, 'esc_html');
4135
+ }
4136
+ return $this->exif_array;
4137
  }
4138
+ // convert a fraction string to a decimal
4139
+ function exif_frac2dec($str)
 
 
 
 
 
 
4140
  {
4141
+ @(list($n, $d) = explode('/', $str));
4142
+ if (!empty($d)) {
4143
+ return $n / $d;
4144
+ }
4145
+ return $str;
4146
+ }
4147
+ // convert the exif date format to a unix timestamp
4148
+ function exif_date2ts($str)
4149
+ {
4150
+ $retval = is_numeric($str) ? $str : @strtotime($str);
4151
+ if (!$retval && $str) {
4152
+ @(list($date, $time) = explode(' ', trim($str)));
4153
+ @(list($y, $m, $d) = explode(':', $date));
4154
+ $retval = strtotime("{$y}-{$m}-{$d} {$time}");
4155
  }
4156
  return $retval;
4157
  }
4158
  /**
4159
+ * nggMeta::readIPTC() - IPTC Data Information for EXIF Display
4160
+ *
4161
+ * @param object $object (optional)
4162
+ * @return null|bool|array
 
4163
  */
4164
+ function get_IPTC($object = false)
4165
  {
4166
+ if (!$this->iptc_data) {
4167
+ return false;
4168
+ }
4169
+ if (!is_array($this->iptc_array)) {
4170
+ // --------- Set up Array Functions --------- //
4171
+ $iptcTags = array("2#005" => 'title', "2#007" => 'status', "2#012" => 'subject', "2#015" => 'category', "2#025" => 'keywords', "2#055" => 'created_date', "2#060" => 'created_time', "2#080" => 'author', "2#085" => 'position', "2#090" => 'city', "2#092" => 'location', "2#095" => 'state', "2#100" => 'country_code', "2#101" => 'country', "2#105" => 'headline', "2#110" => 'credit', "2#115" => 'source', "2#116" => 'copyright', "2#118" => 'contact', "2#120" => 'caption');
4172
+ $meta = array();
4173
+ foreach ($iptcTags as $key => $value) {
4174
+ if (isset($this->iptc_data[$key])) {
4175
+ $meta[$value] = trim($this->utf8_encode(implode(", ", $this->iptc_data[$key])));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4176
  }
4177
  }
4178
+ $this->iptc_array = $meta;
4179
+ }
4180
+ // return one element if requested
4181
+ if ($object) {
4182
+ return isset($this->iptc_array[$object]) ? $this->iptc_array[$object] : NULL;
4183
+ }
4184
+ // on request sanitize the output
4185
+ if ($this->sanitize == true) {
4186
+ array_walk($this->iptc_array, 'esc_html');
4187
+ }
4188
+ return $this->iptc_array;
4189
+ }
4190
+ /**
4191
+ * nggMeta::extract_XMP()
4192
+ * get XMP DATA
4193
+ * code by Pekka Saarinen http://photography-on-the.net
4194
+ *
4195
+ * @param mixed $filename
4196
+ * @return bool|string
4197
+ */
4198
+ function extract_XMP($filename)
4199
+ {
4200
+ //TODO:Require a lot of memory, could be better
4201
+ ob_start();
4202
+ @readfile($filename);
4203
+ $source = ob_get_contents();
4204
+ ob_end_clean();
4205
+ $start = strpos($source, "<x:xmpmeta");
4206
+ $end = strpos($source, "</x:xmpmeta>");
4207
+ if (!$start === false && !$end === false) {
4208
+ $lenght = $end - $start;
4209
+ $xmp_data = substr($source, $start, $lenght + 12);
4210
+ unset($source);
4211
+ return $xmp_data;
4212
+ }
4213
+ unset($source);
4214
+ return false;
4215
+ }
4216
+ /**
4217
+ * nggMeta::get_XMP()
4218
+ *
4219
+ * @package Taken from http://php.net/manual/en/function.xml-parse-into-struct.php
4220
+ * @author Alf Marius Foss Olsen & Alex Rabe
4221
+ * @return bool|array
4222
+ *
4223
+ */
4224
+ function get_XMP($object = false)
4225
+ {
4226
+ if (!$this->xmp_data) {
4227
+ return false;
4228
+ }
4229
+ if (!is_array($this->xmp_array)) {
4230
+ $parser = xml_parser_create();
4231
+ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
4232
+ // Dont mess with my cAsE sEtTings
4233
+ xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4234
+ // Dont bother with empty info
4235
+ xml_parse_into_struct($parser, $this->xmp_data, $values);
4236
+ xml_parser_free($parser);
4237
+ $xmlarray = array();
4238
+ // The XML array
4239
+ $this->xmp_array = array();
4240
+ // The returned array
4241
+ $stack = array();
4242
+ // tmp array used for stacking
4243
+ $list_array = array();
4244
+ // tmp array for list elements
4245
+ $list_element = false;
4246
+ // rdf:li indicator
4247
+ foreach ($values as $val) {
4248
+ if ($val['type'] == "open") {
4249
+ array_push($stack, $val['tag']);
4250
+ } elseif ($val['type'] == "close") {
4251
+ // reset the compared stack
4252
+ if ($list_element == false) {
4253
+ array_pop($stack);
4254
  }
4255
+ // reset the rdf:li indicator & array
4256
+ $list_element = false;
4257
+ $list_array = array();
4258
+ } elseif ($val['type'] == "complete") {
4259
+ if ($val['tag'] == "rdf:li") {
4260
+ // first go one element back
4261
+ if ($list_element == false) {
4262
+ array_pop($stack);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4263
  }
4264
+ $list_element = true;
4265
+ // do not parse empty tags
4266
+ if (empty($val['value'])) {
4267
+ continue;
 
 
4268
  }
4269
+ // save it in our temp array
4270
+ $list_array[] = $val['value'];
4271
+ // in the case it's a list element we seralize it
4272
+ $value = implode(",", $list_array);
4273
+ $this->setArrayValue($xmlarray, $stack, $value);
4274
  } else {
4275
+ array_push($stack, $val['tag']);
4276
+ // do not parse empty tags
4277
+ if (!empty($val['value'])) {
4278
+ $this->setArrayValue($xmlarray, $stack, $val['value']);
 
 
 
 
 
 
 
 
4279
  }
4280
+ array_pop($stack);
 
4281
  }
 
 
 
 
4282
  }
4283
  }
4284
+ // foreach
4285
+ // don't parse a empty array
4286
+ if (empty($xmlarray) || empty($xmlarray['x:xmpmeta'])) {
4287
+ return false;
 
 
 
 
4288
  }
4289
+ // cut off the useless tags
4290
+ $xmlarray = $xmlarray['x:xmpmeta']['rdf:RDF']['rdf:Description'];
4291
+ // --------- Some values from the XMP format--------- //
4292
+ $xmpTags = array('xap:CreateDate' => 'created_timestamp', 'xap:ModifyDate' => 'last_modfied', 'xap:CreatorTool' => 'tool', 'dc:format' => 'format', 'dc:title' => 'title', 'dc:creator' => 'author', 'dc:subject' => 'keywords', 'dc:description' => 'caption', 'photoshop:AuthorsPosition' => 'position', 'photoshop:City' => 'city', 'photoshop:Country' => 'country');
4293
+ foreach ($xmpTags as $key => $value) {
4294
+ // if the kex exist
4295
+ if (isset($xmlarray[$key])) {
4296
+ switch ($key) {
4297
+ case 'xap:CreateDate':
4298
+ case 'xap:ModifyDate':
4299
+ $this->xmp_array[$value] = strtotime($xmlarray[$key]);
4300
+ break;
4301
+ default:
4302
+ $this->xmp_array[$value] = $xmlarray[$key];
4303
+ }
4304
+ }
4305
  }
 
 
4306
  }
4307
+ // return one element if requested
4308
+ if ($object != false) {
4309
+ return isset($this->xmp_array[$object]) ? $this->xmp_array[$object] : false;
4310
+ }
4311
+ // on request sanitize the output
4312
+ if ($this->sanitize == true) {
4313
+ array_walk($this->xmp_array, 'esc_html');
4314
+ }
4315
+ return $this->xmp_array;
4316
+ }
4317
+ function setArrayValue(&$array, $stack, $value)
4318
+ {
4319
+ if ($stack) {
4320
+ $key = array_shift($stack);
4321
+ $this->setArrayValue($array[$key], $stack, $value);
4322
+ return $array;
4323
+ } else {
4324
+ $array = $value;
4325
+ }
4326
+ return $array;
4327
+ }
4328
+ /**
4329
+ * nggMeta::get_META() - return a meta value form the available list
4330
+ *
4331
+ * @param string $object
4332
+ * @return mixed $value
4333
+ */
4334
+ function get_META($object = false)
4335
+ {
4336
+ // defined order first look into database, then XMP, IPTC and EXIF.
4337
+ if ($value = $this->get_saved_meta($object)) {
4338
+ return $value;
4339
+ }
4340
+ if ($value = $this->get_XMP($object)) {
4341
+ return $value;
4342
+ }
4343
+ if ($object == 'created_timestamp' && ($d = $this->get_IPTC('created_date')) && ($t = $this->get_IPTC('created_time'))) {
4344
+ return $this->exif_date2ts($d . ' ' . $t);
4345
+ }
4346
+ if ($value = $this->get_IPTC($object)) {
4347
+ return $value;
4348
+ }
4349
+ if ($value = $this->get_EXIF($object)) {
4350
+ return $value;
4351
+ }
4352
+ // nothing found ?
4353
+ return false;
4354
+ }
4355
+ /**
4356
+ * nggMeta::i8n_name() - localize the tag name
4357
+ *
4358
+ * @param mixed $key
4359
+ * @return string Translated $key
4360
+ */
4361
+ function i18n_name($key)
4362
+ {
4363
+ $tagnames = array('aperture' => __('Aperture', 'nggallery'), 'credit' => __('Credit', 'nggallery'), 'camera' => __('Camera', 'nggallery'), 'caption' => __('Caption', 'nggallery'), 'created_timestamp' => __('Date/Time', 'nggallery'), 'copyright' => __('Copyright', 'nggallery'), 'focal_length' => __('Focal length', 'nggallery'), 'iso' => __('ISO', 'nggallery'), 'shutter_speed' => __('Shutter speed', 'nggallery'), 'title' => __('Title', 'nggallery'), 'author' => __('Author', 'nggallery'), 'tags' => __('Tags', 'nggallery'), 'subject' => __('Subject', 'nggallery'), 'make' => __('Make', 'nggallery'), 'status' => __('Edit Status', 'nggallery'), 'category' => __('Category', 'nggallery'), 'keywords' => __('Keywords', 'nggallery'), 'created_date' => __('Date Created', 'nggallery'), 'created_time' => __('Time Created', 'nggallery'), 'position' => __('Author Position', 'nggallery'), 'city' => __('City', 'nggallery'), 'location' => __('Location', 'nggallery'), 'state' => __('Province/State', 'nggallery'), 'country_code' => __('Country code', 'nggallery'), 'country' => __('Country', 'nggallery'), 'headline' => __('Headline', 'nggallery'), 'credit' => __('Credit', 'nggallery'), 'source' => __('Source', 'nggallery'), 'copyright' => __('Copyright Notice', 'nggallery'), 'contact' => __('Contact', 'nggallery'), 'last_modfied' => __('Last modified', 'nggallery'), 'tool' => __('Program tool', 'nggallery'), 'format' => __('Format', 'nggallery'), 'width' => __('Image Width', 'nggallery'), 'height' => __('Image Height', 'nggallery'), 'flash' => __('Flash', 'nggallery'));
4364
+ if (isset($tagnames[$key])) {
4365
+ $key = $tagnames[$key];
4366
+ }
4367
+ return $key;
4368
  }
4369
  /**
4370
+ * Return the Timestamp from the image , if possible it's read from exif data
4371
+ * @return string
 
 
 
 
4372
  */
4373
+ function get_date_time()
4374
  {
4375
+ $date = time();
4376
+ // Try getting the created_timestamp field
4377
+ $date = $this->exif_date2ts($this->get_META('created_timestamp'));
4378
+ if (!$date) {
4379
+ $image_path = C_Gallery_Storage::get_instance()->get_backup_abspath($this->image);
4380
+ $date = @filectime($image_path);
4381
  }
4382
+ // Failback
4383
+ if (!$date) {
4384
+ $date = time();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4385
  }
4386
+ // Return the MySQL format
4387
+ $date_time = date('Y-m-d H:i:s', $date);
4388
+ return $date_time;
4389
  }
4390
+ /**
4391
+ * This function return the most common metadata, via a filter we can add more
4392
+ * Reason : GD manipulation removes that options
4393
+ *
4394
+ * @since V1.4.0
4395
+ * @return array|false
4396
+ */
4397
+ function get_common_meta()
4398
  {
4399
+ global $wpdb;
4400
+ $meta = array('aperture' => 0, 'credit' => '', 'camera' => '', 'caption' => '', 'created_timestamp' => 0, 'copyright' => '', 'focal_length' => 0, 'iso' => 0, 'shutter_speed' => 0, 'flash' => 0, 'title' => '', 'keywords' => '');
4401
+ $meta = apply_filters('ngg_read_image_metadata', $meta);
4402
+ // meta should be still an array
4403
+ if (!is_array($meta)) {
4404
+ return false;
4405
  }
4406
+ foreach ($meta as $key => $value) {
4407
+ $meta[$key] = $this->get_META($key);
4408
  }
4409
+ //let's add now the size of the image
4410
+ $meta['width'] = $this->size[0];
4411
+ $meta['height'] = $this->size[1];
4412
+ return $meta;
4413
  }
4414
+ /**
4415
+ * If needed sanitize each value before output
4416
+ *
4417
+ * @return void
4418
+ */
4419
+ function sanitize()
4420
  {
4421
+ $this->sanitize = true;
4422
+ }
4423
+ /**
4424
+ * Wrapper to utf8_encode() that avoids double encoding
4425
+ *
4426
+ * Regex adapted from http://www.w3.org/International/questions/qa-forms-utf-8.en.php
4427
+ * to determine if the given string is already UTF-8. mb_detect_encoding() is not
4428
+ * always available and is limited in accuracy
4429
+ *
4430
+ * @param string $str
4431
+ * @return string
4432
+ */
4433
+ function utf8_encode($str)
4434
+ {
4435
+ $is_utf8 = preg_match('%^(?:
4436
+ [\\x09\\x0A\\x0D\\x20-\\x7E] # ASCII
4437
+ | [\\xC2-\\xDF][\\x80-\\xBF] # non-overlong 2-byte
4438
+ | \\xE0[\\xA0-\\xBF][\\x80-\\xBF] # excluding overlongs
4439
+ | [\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2} # straight 3-byte
4440
+ | \\xED[\\x80-\\x9F][\\x80-\\xBF] # excluding surrogates
4441
+ | \\xF0[\\x90-\\xBF][\\x80-\\xBF]{2} # planes 1-3
4442
+ | [\\xF1-\\xF3][\\x80-\\xBF]{3} # planes 4-15
4443
+ | \\xF4[\\x80-\\x8F][\\x80-\\xBF]{2} # plane 16
4444
+ )*$%xs', $str);
4445
+ if (!$is_utf8) {
4446
+ utf8_encode($str);
4447
  }
4448
+ return $str;
 
 
 
4449
  }
4450
+ }
4451
+ /**
4452
+ * gd.thumbnail.inc.php
4453
+ *
4454
+ * @author Ian Selby (ian@gen-x-design.com)
4455
+ * @copyright Copyright 2006-2011
4456
+ * @version 1.3.0 (based on 1.1.3)
4457
+ * @modded by Alex Rabe
4458
+ *
4459
+ */
4460
+ /**
4461
+ * PHP class for dynamically resizing, cropping, and rotating images for thumbnail purposes and either displaying them on-the-fly or saving them.
4462
+ *
4463
+ */
4464
+ class C_NggLegacy_Thumbnail
4465
+ {
4466
+ /**
4467
+ * Error message to display, if any
4468
+ *
4469
+ * @var string
4470
+ */
4471
+ var $errmsg;
4472
+ /**
4473
+ * Whether or not there is an error
4474
+ *
4475
+ * @var boolean
4476
+ */
4477
+ var $error;
4478
+ /**
4479
+ * Format of the image file
4480
+ *
4481
+ * @var string
4482
+ */
4483
+ var $format;
4484
+ /**
4485
+ * File name and path of the image file
4486
+ *
4487
+ * @var string
4488
+ */
4489
+ var $fileName;
4490
+ /**
4491
+ * Current dimensions of working image
4492
+ *
4493
+ * @var array
4494
+ */
4495
+ var $currentDimensions;
4496
+ /**
4497
+ * New dimensions of working image
4498
+ *
4499
+ * @var array
4500
+ */
4501
+ var $newDimensions;
4502
+ /**
4503
+ * Image resource for newly manipulated image
4504
+ *
4505
+ * @var resource
4506
+ * @access private
4507
+ */
4508
+ var $newImage;
4509
+ /**
4510
+ * Image resource for image before previous manipulation
4511
+ *
4512
+ * @var resource
4513
+ * @access private
4514
+ */
4515
+ var $oldImage;
4516
+ /**
4517
+ * Image resource for image being currently manipulated
4518
+ *
4519
+ * @var resource
4520
+ * @access private
4521
+ */
4522
+ var $workingImage;
4523
+ /**
4524
+ * Percentage to resize image by
4525
+ *
4526
+ * @var int
4527
+ * @access private
4528
+ */
4529
+ var $percent;
4530
+ /**
4531
+ * Maximum width of image during resize
4532
+ *
4533
+ * @var int
4534
+ * @access private
4535
+ */
4536
+ var $maxWidth;
4537
+ /**
4538
+ * Maximum height of image during resize
4539
+ *
4540
+ * @var int
4541
+ * @access private
4542
+ */
4543
+ var $maxHeight;
4544
+ /**
4545
+ * Image for Watermark
4546
+ *
4547
+ * @var string
4548
+ *
4549
+ */
4550
+ var $watermarkImgPath;
4551
+ /**
4552
+ * Text for Watermark
4553
+ *
4554
+ * @var string
4555
+ *
4556
+ */
4557
+ var $watermarkText;
4558
  /**
4559
+ * Image Resource ID for Watermark
4560
+ *
4561
+ * @var string
4562
+ *
 
 
 
4563
  */
4564
+ function __construct($fileName, $no_ErrorImage = false)
4565
  {
4566
+ //make sure the GD library is installed
4567
+ if (!function_exists("gd_info")) {
4568
+ echo 'You do not have the GD Library installed. This class requires the GD library to function properly.' . "\n";
4569
+ echo 'visit http://us2.php.net/manual/en/ref.image.php for more information';
4570
+ throw new E_No_Image_Library_Exception();
4571
  }
4572
+ //initialize variables
4573
+ $this->errmsg = '';
4574
+ $this->error = false;
4575
+ $this->currentDimensions = array();
4576
+ $this->newDimensions = array();
4577
+ $this->fileName = $fileName;
4578
+ $this->percent = 100;
4579
+ $this->maxWidth = 0;
4580
+ $this->maxHeight = 0;
4581
+ $this->watermarkImgPath = '';
4582
+ $this->watermarkText = '';
4583
+ //check to see if file exists
4584
+ if (!@file_exists($this->fileName)) {
4585
+ $this->errmsg = 'File not found';
4586
+ $this->error = true;
4587
+ } elseif (!is_readable($this->fileName)) {
4588
+ $this->errmsg = 'File is not readable';
4589
+ $this->error = true;
4590
  }
4591
+ $image_size = null;
4592
+ //if there are no errors, determine the file format
4593
+ if ($this->error == false) {
4594
+ // set_time_limit(30);
4595
+ @ini_set('memory_limit', -1);
4596
+ $image_size = @getimagesize($this->fileName);
4597
+ if (isset($image_size) && is_array($image_size)) {
4598
+ $extensions = array('1' => 'GIF', '2' => 'JPG', '3' => 'PNG');
4599
+ $extension = array_key_exists($image_size[2], $extensions) ? $extensions[$image_size[2]] : '';
4600
+ if ($extension) {
4601
+ $this->format = $extension;
4602
+ } else {
4603
+ $this->errmsg = 'Unknown file format';
4604
+ $this->error = true;
4605
+ }
4606
+ } else {
4607
+ $this->errmsg = 'File is not an image';
4608
+ $this->error = true;
4609
+ }
4610
  }
4611
+ // increase memory-limit if possible, GD needs this for large images
4612
+ if (!extension_loaded('suhosin')) {
4613
+ @ini_set('memory_limit', '512M');
4614
  }
4615
+ if ($this->error == false) {
4616
+ // Check memory consumption if file exists
4617
+ $this->checkMemoryForImage($this->fileName);
4618
  }
4619
+ //initialize resources if no errors
4620
+ if ($this->error == false) {
4621
+ $img_err = null;
4622
+ switch ($this->format) {
4623
+ case 'GIF':
4624
+ if (function_exists('ImageCreateFromGif')) {
4625
+ $this->oldImage = @ImageCreateFromGif($this->fileName);
4626
+ } else {
4627
+ $img_err = __('Support for GIF format is missing.', 'nggallery');
4628
+ }
4629
+ break;
4630
+ case 'JPG':
4631
+ if (function_exists('ImageCreateFromJpeg')) {
4632
+ $this->oldImage = @ImageCreateFromJpeg($this->fileName);
4633
+ } else {
4634
+ $img_err = __('Support for JPEG format is missing.', 'nggallery');
4635
+ }
4636
+ break;
4637
+ case 'PNG':
4638
+ if (function_exists('ImageCreateFromPng')) {
4639
+ $this->oldImage = @ImageCreateFromPng($this->fileName);
4640
+ } else {
4641
+ $img_err = __('Support for PNG format is missing.', 'nggallery');
4642
+ }
4643
+ break;
4644
+ }
4645
+ if (!$this->oldImage) {
4646
+ if ($img_err == null) {
4647
+ $img_err = __('Check memory limit', 'nggallery');
4648
+ }
4649
+ $this->errmsg = sprintf(__('Create Image failed. %1$s', 'nggallery'), $img_err);
4650
+ $this->error = true;
4651
+ } else {
4652
+ $this->currentDimensions = array('width' => $image_size[0], 'height' => $image_size[1]);
4653
+ $this->newImage = $this->oldImage;
4654
+ }
4655
  }
4656
+ if ($this->error == true) {
4657
+ if (!$no_ErrorImage) {
4658
+ $this->showErrorImage();
4659
+ }
4660
+ return;
4661
  }
4662
  }
4663
  /**
4664
+ * Calculate the memory limit
4665
+ * @param string $filename
4666
+ *
4667
  */
4668
+ function checkMemoryForImage($filename)
4669
  {
4670
+ $imageInfo = getimagesize($filename);
4671
+ switch ($this->format) {
4672
+ case 'GIF':
4673
+ // measured factor 1 is better
4674
+ $CHANNEL = 1;
4675
+ break;
4676
+ case 'JPG':
4677
+ $CHANNEL = $imageInfo['channels'];
4678
+ break;
4679
+ case 'PNG':
4680
+ // didn't get the channel for png
4681
+ $CHANNEL = 3;
4682
+ break;
4683
  }
4684
+ $bits = !empty($imageInfo['bits']) ? $imageInfo['bits'] : 32;
4685
+ // imgInfo[bits] is not always available
4686
+ return $this->checkMemoryForData($imageInfo[0], $imageInfo[1], $CHANNEL, $bits);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4687
  }
4688
+ function checkMemoryForData($width, $height, $channels = null, $bits = null)
 
 
 
 
 
 
4689
  {
4690
+ $imageInfo = getimagesize($this->fileName);
4691
+ if ($channels == null) {
4692
+ switch ($this->format) {
4693
+ case 'GIF':
4694
+ // measured factor 1 is better
4695
+ $channels = 1;
4696
+ break;
4697
+ case 'JPG':
4698
+ $channels = $imageInfo['channels'];
4699
+ break;
4700
+ case 'PNG':
4701
+ // didn't get the channel for png
4702
+ $channels = 3;
4703
+ break;
4704
  }
 
 
4705
  }
4706
+ if ($bits == null) {
4707
+ $bits = !empty($imageInfo['bits']) ? $imageInfo['bits'] : 32;
4708
+ }
4709
+ // imgInfo[bits] is not always available
4710
+ if (function_exists('memory_get_usage') && ini_get('memory_limit')) {
4711
+ $MB = 1048576;
4712
+ // number of bytes in 1M
4713
+ $K64 = 65536;
4714
+ // number of bytes in 64K
4715
+ $TWEAKFACTOR = 1.68;
4716
+ // Or whatever works for you
4717
+ $memoryNeeded = round((doubleval($width * $height * $bits * $channels) / 8 + $K64) * $TWEAKFACTOR);
4718
+ $memoryNeeded = memory_get_usage() + $memoryNeeded;
4719
+ // get memory limit
4720
+ $memory_limit = ini_get('memory_limit');
4721
+ // PHP docs : Note that to have no memory limit, set this directive to -1.
4722
+ if ($memory_limit == -1) {
4723
+ return true;
4724
+ }
4725
+ // Just check megabyte limits, not higher
4726
+ if (strtolower(substr($memory_limit, -1)) == 'm') {
4727
+ if ($memory_limit != '') {
4728
+ $memory_limit = intval(substr($memory_limit, 0, -1)) * 1024 * 1024;
4729
+ }
4730
+ if ($memoryNeeded > $memory_limit) {
4731
+ $memoryNeeded = round($memoryNeeded / 1024 / 1024, 2);
4732
+ $this->errmsg = 'Exceed Memory limit. Require : ' . $memoryNeeded . " MByte";
4733
+ $this->error = true;
4734
+ return false;
4735
+ }
4736
+ }
4737
  }
4738
+ return true;
 
 
 
 
4739
  }
4740
+ function __destruct()
4741
  {
4742
+ $this->destruct();
4743
  }
4744
  /**
4745
+ * Must be called to free up allocated memory after all manipulations are done
 
 
4746
  *
 
 
4747
  */
4748
+ function destruct()
4749
  {
4750
+ if (is_resource($this->newImage)) {
4751
+ @ImageDestroy($this->newImage);
4752
+ }
4753
+ if (is_resource($this->oldImage)) {
4754
+ @ImageDestroy($this->oldImage);
4755
+ }
4756
+ if (is_resource($this->workingImage)) {
4757
+ @ImageDestroy($this->workingImage);
4758
+ }
4759
  }
4760
  /**
4761
+ * Returns the current width of the image
4762
+ *
4763
+ * @return int
4764
  */
4765
+ function getCurrentWidth()
4766
  {
4767
+ return $this->currentDimensions['width'];
4768
  }
4769
  /**
4770
+ * Returns the current height of the image
4771
+ *
4772
+ * @return int
4773
  */
4774
+ function getCurrentHeight()
4775
  {
4776
+ return $this->currentDimensions['height'];
4777
  }
4778
  /**
4779
+ * Calculates new image width
4780
+ *
4781
+ * @param int $width
4782
+ * @param int $height
4783
+ * @return array
4784
  */
4785
+ function calcWidth($width, $height)
4786
  {
4787
+ $newWp = 100 * $this->maxWidth / $width;
4788
+ $newHeight = $height * $newWp / 100;
4789
+ if (intval($newHeight) == $this->maxHeight - 1) {
4790
+ $newHeight = $this->maxHeight;
4791
+ }
4792
+ return array('newWidth' => intval($this->maxWidth), 'newHeight' => intval($newHeight));
4793
  }
4794
  /**
4795
+ * Calculates new image height
4796
  *
4797
+ * @param int $width
4798
+ * @param int $height
4799
+ * @return array
4800
  */
4801
+ function calcHeight($width, $height)
 
 
 
 
 
 
 
 
4802
  {
4803
+ $newHp = 100 * $this->maxHeight / $height;
4804
+ $newWidth = $width * $newHp / 100;
4805
+ if (intval($newWidth) == $this->maxWidth - 1) {
4806
+ $newWidth = $this->maxWidth;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4807
  }
4808
+ return array('newWidth' => intval($newWidth), 'newHeight' => intval($this->maxHeight));
4809
  }
4810
  /**
4811
+ * Calculates new image size based on percentage
4812
+ *
4813
+ * @param int $width
4814
+ * @param int $height
4815
+ * @return array
4816
  */
4817
+ function calcPercent($width, $height, $percent = -1)
 
 
 
 
 
 
 
 
4818
  {
4819
+ if ($percent == -1) {
4820
+ $percent = $this->percent;
 
 
4821
  }
4822
+ $newWidth = $width * $percent / 100;
4823
+ $newHeight = $height * $percent / 100;
4824
+ return array('newWidth' => intval($newWidth), 'newHeight' => intval($newHeight));
4825
  }
4826
  /**
4827
+ * Calculates new image size based on width and height, while constraining to maxWidth and maxHeight
4828
+ *
4829
+ * @param int $width
4830
+ * @param int $height
4831
  */
4832
+ function calcImageSize($width, $height)
4833
  {
4834
+ // $width and $height are the CURRENT image resolutions
4835
+ $ratio_w = $this->maxWidth / $width;
4836
+ $ratio_h = $this->maxHeight / $height;
4837
+ if ($ratio_w >= $ratio_h) {
4838
+ $width = $this->maxWidth;
4839
+ $height = (int) round($height * $ratio_h, 0);
4840
+ } else {
4841
+ $height = $this->maxHeight;
4842
+ $width = (int) round($width * $ratio_w, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4843
  }
4844
+ $this->newDimensions = array('newWidth' => $width, 'newHeight' => $height);
4845
  }
4846
  /**
4847
+ * Calculates new image size based percentage
4848
+ *
4849
+ * @param int $width
4850
+ * @param int $height
 
4851
  */
4852
+ function calcImageSizePercent($width, $height)
 
 
 
 
 
 
 
 
 
 
 
 
4853
  {
4854
+ if ($this->percent > 0) {
4855
+ $this->newDimensions = $this->calcPercent($width, $height);
 
4856
  }
 
4857
  }
4858
  /**
4859
+ * Displays error image
4860
  *
 
 
 
4861
  */
4862
+ function showErrorImage()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4863
  {
4864
+ header('Content-type: image/png');
4865
+ $errImg = ImageCreate(220, 25);
4866
+ $bgColor = imagecolorallocate($errImg, 0, 0, 0);
4867
+ $fgColor1 = imagecolorallocate($errImg, 255, 255, 255);
4868
+ $fgColor2 = imagecolorallocate($errImg, 255, 0, 0);
4869
+ imagestring($errImg, 3, 6, 6, 'Error:', $fgColor2);
4870
+ imagestring($errImg, 3, 55, 6, $this->errmsg, $fgColor1);
4871
+ imagepng($errImg);
4872
+ imagedestroy($errImg);
4873
  }
4874
  /**
4875
+ * Resizes image to fixed Width x Height
4876
+ *
4877
+ * @param int $Width
4878
+ * @param int $Height
4879
+ * @param int $deprecated Unused
4880
  */
4881
+ function resizeFix($Width = 0, $Height = 0, $deprecated = 3)
4882
  {
4883
+ if (!$this->checkMemoryForData($Width, $Height)) {
4884
+ return;
 
4885
  }
4886
+ $this->newWidth = $Width;
4887
+ $this->newHeight = $Height;
4888
+ if (function_exists("ImageCreateTrueColor")) {
4889
+ $this->workingImage = ImageCreateTrueColor($this->newWidth, $this->newHeight);
4890
+ } else {
4891
+ $this->workingImage = ImageCreate($this->newWidth, $this->newHeight);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4892
  }
4893
+ // ImageCopyResampled(
4894
+ $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->currentDimensions['width'], $this->currentDimensions['height']);
4895
+ $this->oldImage = $this->workingImage;
4896
+ $this->newImage = $this->workingImage;
4897
+ $this->currentDimensions['width'] = $this->newWidth;
4898
+ $this->currentDimensions['height'] = $this->newHeight;
4899
  }
4900
+ /**
4901
+ * Resizes image to maxWidth x maxHeight
4902
+ *
4903
+ * @param int $maxWidth
4904
+ * @param int $maxHeight
4905
+ * @param int $deprecated Unused
4906
+ */
4907
+ function resize($maxWidth = 0, $maxHeight = 0, $deprecated = 3)
4908
  {
4909
+ if (!$this->checkMemoryForData($maxWidth, $maxHeight)) {
4910
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
4911
  }
4912
+ $this->maxWidth = $maxWidth;
4913
+ $this->maxHeight = $maxHeight;
4914
+ $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']);
4915
+ if ($this->workingImage != null && $this->workingImage != $this->oldImage) {
4916
+ ImageDestroy($this->workingImage);
4917
+ $this->workingImage = null;
 
 
 
 
 
 
 
4918
  }
4919
+ if (function_exists("ImageCreateTrueColor")) {
4920
+ $this->workingImage = ImageCreateTrueColor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
4921
+ } else {
4922
+ $this->workingImage = ImageCreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
4923
+ }
4924
+ // ImageCopyResampled(
4925
+ $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height']);
4926
+ ImageDestroy($this->oldImage);
4927
+ $this->oldImage = $this->workingImage;
4928
+ $this->newImage = $this->workingImage;
4929
+ $this->currentDimensions['width'] = $this->newDimensions['newWidth'];
4930
+ $this->currentDimensions['height'] = $this->newDimensions['newHeight'];
4931
  }
4932
+ /**
4933
+ * Resizes the image by $percent percent
4934
+ *
4935
+ * @param int $percent
4936
+ */
4937
+ function resizePercent($percent = 0)
4938
  {
4939
+ $dims = $this->calcPercent($this->currentDimensions['width'], $this->currentDimensions['height'], $percent);
4940
+ if (!$this->checkMemoryForData($dims['newWidth'], $dims['newHeight'])) {
4941
+ return;
 
 
 
 
 
 
 
 
 
 
 
4942
  }
4943
+ $this->percent = $percent;
4944
+ $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']);
4945
+ if (function_exists("ImageCreateTrueColor")) {
4946
+ $this->workingImage = ImageCreateTrueColor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
4947
+ } else {
4948
+ $this->workingImage = ImageCreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
4949
+ }
4950
+ $this->ImageCopyResampled($this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height']);
4951
+ $this->oldImage = $this->workingImage;
4952
+ $this->newImage = $this->workingImage;
4953
+ $this->currentDimensions['width'] = $this->newDimensions['newWidth'];
4954
+ $this->currentDimensions['height'] = $this->newDimensions['newHeight'];
4955
  }
4956
  /**
4957
+ * Crops the image from calculated center in a square of $cropSize pixels
4958
+ *
4959
+ * @param int $cropSize
 
4960
  */
4961
+ function cropFromCenter($cropSize)
4962
  {
4963
+ if ($cropSize > $this->currentDimensions['width']) {
4964
+ $cropSize = $this->currentDimensions['width'];
 
 
 
 
 
 
 
 
 
 
4965
  }
4966
+ if ($cropSize > $this->currentDimensions['height']) {
4967
+ $cropSize = $this->currentDimensions['height'];
4968
+ }
4969
+ $cropX = intval(($this->currentDimensions['width'] - $cropSize) / 2);
4970
+ $cropY = intval(($this->currentDimensions['height'] - $cropSize) / 2);
4971
+ if ($this->workingImage != null && $this->workingImage != $this->oldImage) {
4972
+ ImageDestroy($this->workingImage);
4973
+ $this->workingImage = null;
4974
+ }
4975
+ if (function_exists("ImageCreateTrueColor")) {
4976
+ $this->workingImage = ImageCreateTrueColor($cropSize, $cropSize);
4977
  } else {
4978
+ $this->workingImage = ImageCreate($cropSize, $cropSize);
 
 
 
 
4979
  }
4980
+ $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, $cropX, $cropY, $cropSize, $cropSize, $cropSize, $cropSize);
4981
+ $this->oldImage = $this->workingImage;
4982
+ $this->newImage = $this->workingImage;
4983
+ $this->currentDimensions['width'] = $cropSize;
4984
+ $this->currentDimensions['height'] = $cropSize;
4985
  }
4986
  /**
4987
+ * Advanced cropping function that crops an image using $startX and $startY as the upper-left hand corner.
4988
+ *
4989
+ * @param int $startX
4990
+ * @param int $startY
4991
+ * @param int $width
4992
+ * @param int $height
4993
  */
4994
+ function crop($startX, $startY, $width, $height)
4995
  {
4996
+ if (!$this->checkMemoryForData($width, $height)) {
4997
+ return;
 
4998
  }
4999
+ //make sure the cropped area is not greater than the size of the image
5000
+ if ($width > $this->currentDimensions['width']) {
5001
+ $width = $this->currentDimensions['width'];
 
 
 
 
 
 
5002
  }
5003
+ if ($height > $this->currentDimensions['height']) {
5004
+ $height = $this->currentDimensions['height'];
 
 
 
 
 
5005
  }
5006
+ //make sure not starting outside the image
5007
+ if ($startX + $width > $this->currentDimensions['width']) {
5008
+ $startX = $this->currentDimensions['width'] - $width;
 
 
 
 
5009
  }
5010
+ if ($startY + $height > $this->currentDimensions['height']) {
5011
+ $startY = $this->currentDimensions['height'] - $height;
5012
+ }
5013
+ if ($startX < 0) {
5014
+ $startX = 0;
5015
+ }
5016
+ if ($startY < 0) {
5017
+ $startY = 0;
5018
+ }
5019
+ if ($this->workingImage != null && $this->workingImage != $this->oldImage) {
5020
+ ImageDestroy($this->workingImage);
5021
+ $this->workingImage = null;
5022
+ }
5023
+ if (function_exists("ImageCreateTrueColor")) {
5024
+ $this->workingImage = ImageCreateTrueColor($width, $height);
5025
+ } else {
5026
+ $this->workingImage = ImageCreate($width, $height);
5027
+ }
5028
+ $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, $startX, $startY, $width, $height, $width, $height);
5029
+ ImageDestroy($this->oldImage);
5030
+ $this->oldImage = $this->workingImage;
5031
+ $this->newImage = $this->workingImage;
5032
+ $this->currentDimensions['width'] = $width;
5033
+ $this->currentDimensions['height'] = $height;
5034
+ }
5035
+ /**
5036
+ * Outputs the image to the screen, or saves to $name if supplied. Quality of JPEG images can be controlled with the $quality variable
5037
+ *
5038
+ * @param int $quality
5039
+ * @param string $name
5040
+ */
5041
+ function show($quality = 100, $name = '')
5042
+ {
5043
+ switch ($this->format) {
5044
+ case 'GIF':
5045
+ if ($name != '') {
5046
+ @ImageGif($this->newImage, $name) or $this->error = true;
5047
  } else {
5048
+ header('Content-type: image/gif');
5049
+ ImageGif($this->newImage);
 
 
 
 
5050
  }
5051
+ break;
5052
+ case 'JPG':
5053
+ if ($name != '') {
5054
+ @ImageJpeg($this->newImage, $name, $quality) or $this->error = true;
 
 
 
 
 
 
 
 
5055
  } else {
5056
+ header('Content-type: image/jpeg');
5057
+ ImageJpeg($this->newImage, NULL, $quality);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5058
  }
5059
+ break;
5060
+ case 'PNG':
5061
+ if ($name != '') {
5062
+ @ImagePng($this->newImage, $name) or $this->error = true;
5063
+ } else {
5064
+ header('Content-type: image/png');
5065
+ ImagePng($this->newImage);
5066
  }
5067
+ break;
5068
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5069
  }
5070
  /**
5071
+ * Saves image as $name (can include file path), with quality of # percent if file is a jpeg
5072
+ *
5073
+ * @param string $name
5074
+ * @param int $quality
5075
+ * @return bool errorstate
5076
  */
5077
+ function save($name, $quality = 100)
5078
  {
5079
+ $this->show($quality, $name);
5080
+ if ($this->error == true) {
5081
+ $this->errmsg = 'Create Image failed. Check safe mode settings';
5082
+ return false;
5083
+ }
5084
+ if (function_exists('do_action')) {
5085
+ do_action('ngg_ajax_image_save', $name);
5086
+ }
5087
+ return true;
5088
  }
5089
  /**
5090
+ * Creates Apple-style reflection under image, optionally adding a border to main image
5091
+ *
5092
+ * @param int $percent
5093
+ * @param int $reflection
5094
+ * @param int $white
5095
+ * @param bool $border
5096
+ * @param string $borderColor
5097
  */
5098
+ function createReflection($percent, $reflection, $white, $border = true, $borderColor = '#a4a4a4')
5099
  {
5100
+ $width = $this->currentDimensions['width'];
5101
+ $height = $this->currentDimensions['height'];
5102
+ $reflectionHeight = intval($height * ($reflection / 100));
5103
+ $newHeight = $height + $reflectionHeight;
5104
+ $reflectedPart = $height * ($percent / 100);
5105
+ $this->workingImage = ImageCreateTrueColor($width, $newHeight);
5106
+ ImageAlphaBlending($this->workingImage, true);
5107
+ $colorToPaint = ImageColorAllocateAlpha($this->workingImage, 255, 255, 255, 0);
5108
+ ImageFilledRectangle($this->workingImage, 0, 0, $width, $newHeight, $colorToPaint);
5109
+ imagecopyresampled($this->workingImage, $this->newImage, 0, 0, 0, $reflectedPart, $width, $reflectionHeight, $width, $height - $reflectedPart);
5110
+ $this->imageFlipVertical();
5111
+ imagecopy($this->workingImage, $this->newImage, 0, 0, 0, 0, $width, $height);
5112
+ imagealphablending($this->workingImage, true);
5113
+ for ($i = 0; $i < $reflectionHeight; $i++) {
5114
+ $colorToPaint = imagecolorallocatealpha($this->workingImage, 255, 255, 255, ($i / $reflectionHeight * -1 + 1) * $white);
5115
+ imagefilledrectangle($this->workingImage, 0, $height + $i, $width, $height + $i, $colorToPaint);
5116
  }
5117
+ if ($border == true) {
5118
+ $rgb = $this->hex2rgb($borderColor, false);
5119
+ $colorToPaint = imagecolorallocate($this->workingImage, $rgb[0], $rgb[1], $rgb[2]);
5120
+ imageline($this->workingImage, 0, 0, $width, 0, $colorToPaint);
5121
+ //top line
5122
+ imageline($this->workingImage, 0, $height, $width, $height, $colorToPaint);
5123
+ //bottom line
5124
+ imageline($this->workingImage, 0, 0, 0, $height, $colorToPaint);
5125
+ //left line
5126
+ imageline($this->workingImage, $width - 1, 0, $width - 1, $height, $colorToPaint);
5127
+ //right line
5128
  }
5129
+ $this->oldImage = $this->workingImage;
5130
+ $this->newImage = $this->workingImage;
5131
+ $this->currentDimensions['width'] = $width;
5132
+ $this->currentDimensions['height'] = $newHeight;
5133
  }
5134
  /**
5135
+ * Flip an image.
5136
+ *
5137
+ * @param bool $horz flip the image in horizontal mode
5138
+ * @param bool $vert flip the image in vertical mode
5139
+ * @return true
5140
  */
5141
+ function flipImage($horz = false, $vert = false)
5142
  {
5143
+ $sx = $vert ? $this->currentDimensions['width'] - 1 : 0;
5144
+ $sy = $horz ? $this->currentDimensions['height'] - 1 : 0;
5145
+ $sw = $vert ? -$this->currentDimensions['width'] : $this->currentDimensions['width'];
5146
+ $sh = $horz ? -$this->currentDimensions['height'] : $this->currentDimensions['height'];
5147
+ $this->workingImage = imagecreatetruecolor($this->currentDimensions['width'], $this->currentDimensions['height']);
5148
+ $this->imagecopyresampled($this->workingImage, $this->oldImage, 0, 0, $sx, $sy, $this->currentDimensions['width'], $this->currentDimensions['height'], $sw, $sh);
5149
+ $this->oldImage = $this->workingImage;
5150
+ $this->newImage = $this->workingImage;
5151
+ return true;
5152
  }
 
 
 
 
 
 
 
5153
  /**
5154
+ * Rotate an image clockwise or counter clockwise
 
5155
  *
5156
+ * @param string $dir Either CW or CCW
5157
+ * @return bool
 
5158
  */
5159
+ function rotateImage($dir = 'CW')
 
 
 
 
 
 
 
 
 
 
5160
  {
5161
+ $angle = $dir == 'CW' ? 90 : -90;
5162
+ return $this->rotateImageAngle($angle);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5163
  }
5164
  /**
5165
+ * Rotate an image clockwise or counter clockwise
5166
  *
5167
+ * @param int $angle Degrees to rotate the target image
 
5168
  * @return bool
5169
  */
5170
+ function rotateImageAngle($angle = 90)
5171
  {
5172
+ if (function_exists('imagerotate')) {
5173
+ $this->currentDimensions['width'] = imagesx($this->workingImage);
5174
+ $this->currentDimensions['height'] = imagesy($this->workingImage);
5175
+ $this->oldImage = $this->workingImage;
5176
+ // imagerotate() rotates CCW ;
5177
+ // See for help: https://evertpot.com/115/
5178
+ $this->newImage = imagerotate($this->oldImage, 360 - $angle, 0);
5179
+ return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
5180
  }
5181
+ $this->workingImage = imagecreatetruecolor($this->currentDimensions['height'], $this->currentDimensions['width']);
5182
+ imagealphablending($this->workingImage, false);
5183
+ imagesavealpha($this->workingImage, true);
5184
+ switch ($angle) {
5185
+ case 90:
5186
+ for ($x = 0; $x < $this->currentDimensions['width']; $x++) {
5187
+ for ($y = 0; $y < $this->currentDimensions['height']; $y++) {
5188
+ if (!imagecopy($this->workingImage, $this->oldImage, $this->currentDimensions['height'] - $y - 1, $x, $x, $y, 1, 1)) {
5189
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5190
  }
 
5191
  }
5192
+ }
5193
+ break;
5194
+ case -90:
5195
+ for ($x = 0; $x < $this->currentDimensions['width']; $x++) {
5196
+ for ($y = 0; $y < $this->currentDimensions['height']; $y++) {
5197
+ if (!imagecopy($this->workingImage, $this->oldImage, $y, $this->currentDimensions['width'] - $x - 1, $x, $y, 1, 1)) {
5198
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
5199
  }
5200
  }
 
 
5201
  }
5202
+ break;
5203
+ default:
5204
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5205
  }
5206
+ $this->currentDimensions['width'] = imagesx($this->workingImage);
5207
+ $this->currentDimensions['height'] = imagesy($this->workingImage);
5208
+ $this->oldImage = $this->workingImage;
5209
+ $this->newImage = $this->workingImage;
5210
+ return true;
5211
  }
5212
  /**
5213
+ * Inverts working image, used by reflection function
5214
+ *
5215
+ * @access private
5216
  */
5217
+ function imageFlipVertical()
5218
  {
5219
+ $x_i = imagesx($this->workingImage);
5220
+ $y_i = imagesy($this->workingImage);
5221
+ for ($x = 0; $x < $x_i; $x++) {
5222
+ for ($y = 0; $y < $y_i; $y++) {
5223
+ imagecopy($this->workingImage, $this->workingImage, $x, $y_i - $y - 1, $x, $y, 1, 1);
5224
+ }
 
 
 
 
 
 
 
 
 
5225
  }
 
5226
  }
5227
+ /**
5228
+ * Converts hexidecimal color value to rgb values and returns as array/string
5229
+ *
5230
+ * @param string $hex
5231
+ * @param bool $asString
5232
+ * @return array|string
5233
+ */
5234
+ function hex2rgb($hex, $asString = false)
5235
  {
5236
+ // strip off any leading #
5237
+ if (0 === strpos($hex, '#')) {
5238
+ $hex = substr($hex, 1);
5239
+ } else {
5240
+ if (0 === strpos($hex, '&H')) {
5241
+ $hex = substr($hex, 2);
5242
+ }
5243
  }
5244
+ // break into hex 3-tuple
5245
+ $cutpoint = ceil(strlen($hex) / 2) - 1;
5246
+ $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3);
5247
+ // convert each tuple to decimal
5248
+ $rgb[0] = isset($rgb[0]) ? hexdec($rgb[0]) : 0;
5249
+ $rgb[1] = isset($rgb[1]) ? hexdec($rgb[1]) : 0;
5250
+ $rgb[2] = isset($rgb[2]) ? hexdec($rgb[2]) : 0;
5251
+ return $asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb;
5252
  }
5253
+ /**
5254
+ * Based on the Watermark function by Marek Malcherek
5255
+ * http://www.malcherek.de
5256
+ *
5257
+ * @param string $color
5258
+ * @param string $wmFont
5259
+ * @param int $wmSize
5260
+ * @param int $wmOpaque
5261
+ */
5262
+ function watermarkCreateText($color = '000000', $wmFont, $wmSize = 10, $wmOpaque = 90)
5263
  {
5264
+ // set font path
5265
+ $wmFontPath = NGGALLERY_ABSPATH . "fonts/" . $wmFont;
5266
+ if (!is_readable($wmFontPath)) {
5267
+ return;
5268
  }
5269
+ // This function requires both the GD library and the FreeType library.
5270
+ if (!function_exists('ImageTTFBBox')) {
5271
+ return;
5272
+ }
5273
+ $words = preg_split('/ /', $this->watermarkText);
5274
+ $lines = array();
5275
+ $line = '';
5276
+ $watermark_image_width = 0;
5277
+ // attempt adding a new word until the width is too large; then start a new line and start again
5278
+ foreach ($words as $word) {
5279
+ // sanitize the text being input; imagettftext() can be sensitive
5280
+ $TextSize = $this->ImageTTFBBoxDimensions($wmSize, 0, $this->correct_gd_unc_path($wmFontPath), $line . preg_replace('~^(&([a-zA-Z0-9]);)~', htmlentities('${1}'), mb_convert_encoding($word, "HTML-ENTITIES", "UTF-8")));
5281
+ if ($watermark_image_width == 0) {
5282
+ $watermark_image_width = $TextSize['width'];
5283
+ }
5284
+ if ($TextSize['width'] > $this->newDimensions['newWidth']) {
5285
+ $lines[] = trim($line);
5286
+ $line = '';
5287
  } else {
5288
+ if ($TextSize['width'] > $watermark_image_width) {
5289
+ $watermark_image_width = $TextSize['width'];
 
5290
  }
 
 
5291
  }
5292
+ $line .= $word . ' ';
5293
  }
5294
+ $lines[] = trim($line);
5295
+ // use this string to determine our largest possible line height
5296
+ $line_dimensions = $this->ImageTTFBBoxDimensions($wmSize, 0, $this->correct_gd_unc_path($wmFontPath), 'MXQJALYmxqjabdfghjklpqry019`@$^&*(,!132');
5297
+ $line_height = $line_dimensions['height'] * 1.05;
5298
+ // Create an image to apply our text to
5299
+ $this->workingImage = ImageCreateTrueColor($watermark_image_width, count($lines) * $line_height);
5300
+ ImageSaveAlpha($this->workingImage, true);
5301
+ ImageAlphaBlending($this->workingImage, false);
5302
+ $bgText = imagecolorallocatealpha($this->workingImage, 255, 255, 255, 127);
5303
+ imagefill($this->workingImage, 0, 0, $bgText);
5304
+ $wmTransp = 127 - $wmOpaque * 1.27;
5305
+ $rgb = $this->hex2rgb($color, false);
5306
+ $TextColor = imagecolorallocatealpha($this->workingImage, $rgb[0], $rgb[1], $rgb[2], $wmTransp);
5307
+ // Put text on the image, line-by-line
5308
+ $y_pos = $wmSize;
5309
+ foreach ($lines as $line) {
5310
+ imagettftext($this->workingImage, $wmSize, 0, 0, $y_pos, $TextColor, $this->correct_gd_unc_path($wmFontPath), $line);
5311
+ $y_pos += $line_height;
5312
+ }
5313
+ $this->watermarkImgPath = $this->workingImage;
5314
+ return;
5315
  }
5316
  /**
5317
+ * Returns a path that can be used with imagettftext() and ImageTTFBBox()
5318
  *
5319
+ * imagettftext() and ImageTTFBBox() cannot load resources from Windows UNC paths
5320
+ * and require they be mangled to be like //server\filename instead of \\server\filename
5321
+ * @param string $path Absolute file path
5322
+ * @return string $path Mangled absolute file path
5323
  */
5324
+ public function correct_gd_unc_path($path)
5325
  {
5326
+ if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && substr($path, 0, 2) === '\\\\') {
5327
+ $path = ltrim($path, '\\\\');
5328
+ $path = '//' . $path;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5329
  }
5330
+ return $path;
5331
  }
 
 
 
 
 
 
 
 
5332
  /**
5333
+ * Calculates the width & height dimensions of ImageTTFBBox().
5334
  *
5335
+ * Note: ImageTTFBBox() is unreliable with large font sizes
5336
+ * @param $wmSize
5337
+ * @param $fontAngle
5338
+ * @param $wmFontPath
5339
+ * @param $text
5340
+ * @return array
5341
  */
5342
+ function ImageTTFBBoxDimensions($wmSize, $fontAngle, $wmFontPath, $text)
5343
  {
5344
+ $box = @ImageTTFBBox($wmSize, $fontAngle, $this->correct_gd_unc_path($wmFontPath), $text);
5345
+ $max_x = max(array($box[0], $box[2], $box[4], $box[6]));
5346
+ $max_y = max(array($box[1], $box[3], $box[5], $box[7]));
5347
+ $min_x = min(array($box[0], $box[2], $box[4], $box[6]));
5348
+ $min_y = min(array($box[1], $box[3], $box[5], $box[7]));
5349
+ return array("width" => $max_x - $min_x, "height" => $max_y - $min_y);
5350
+ }
5351
+ function applyFilter($filterType)
5352
+ {
5353
+ $args = func_get_args();
5354
+ array_unshift($args, $this->newImage);
5355
+ return call_user_func_array('imagefilter', $args);
5356
+ }
5357
+ /**
5358
+ * Modfied Watermark function by Steve Peart
5359
+ * http://parasitehosting.com/
5360
+ *
5361
+ * @param string $relPOS
5362
+ * @param int $xPOS
5363
+ * @param int $yPOS
5364
+ */
5365
+ function watermarkImage($relPOS = 'botRight', $xPOS = 0, $yPOS = 0)
5366
+ {
5367
+ // if it's a resource ID take it as watermark text image
5368
+ if (is_resource($this->watermarkImgPath)) {
5369
+ $this->workingImage = $this->watermarkImgPath;
5370
+ } else {
5371
+ // (possibly) search for the file from the document root
5372
+ if (!is_file($this->watermarkImgPath)) {
5373
+ $fs = C_Fs::get_instance();
5374
+ if (is_file($fs->join_paths($fs->get_document_root('content'), $this->watermarkImgPath))) {
5375
+ $this->watermarkImgPath = $fs->get_document_root('content') . $this->watermarkImgPath;
5376
+ }
5377
  }
5378
+ // Would you really want to use anything other than a png?
5379
+ $this->workingImage = @imagecreatefrompng($this->watermarkImgPath);
5380
+ // if it's not a valid file die...
5381
+ if (empty($this->workingImage) or !$this->workingImage) {
5382
+ return;
 
 
 
 
5383
  }
5384
  }
5385
+ imagealphablending($this->workingImage, false);
5386
+ imagesavealpha($this->workingImage, true);
5387
+ $sourcefile_width = imageSX($this->oldImage);
5388
+ $sourcefile_height = imageSY($this->oldImage);
5389
+ $watermarkfile_width = imageSX($this->workingImage);
5390
+ $watermarkfile_height = imageSY($this->workingImage);
5391
+ switch (substr($relPOS, 0, 3)) {
5392
+ case 'top':
5393
+ $dest_y = 0 + $yPOS;
5394
+ break;
5395
+ case 'mid':
5396
+ $dest_y = $sourcefile_height / 2 - $watermarkfile_height / 2;
5397
+ break;
5398
+ case 'bot':
5399
+ $dest_y = $sourcefile_height - $watermarkfile_height - $yPOS;
5400
+ break;
5401
+ default:
5402
+ $dest_y = 0;
5403
+ break;
5404
+ }
5405
+ switch (substr($relPOS, 3)) {
5406
+ case 'Left':
5407
+ $dest_x = 0 + $xPOS;
5408
+ break;
5409
+ case 'Center':
5410
+ $dest_x = $sourcefile_width / 2 - $watermarkfile_width / 2;
5411
+ break;
5412
+ case 'Right':
5413
+ $dest_x = $sourcefile_width - $watermarkfile_width - $xPOS;
5414
+ break;
5415
+ default:
5416
+ $dest_x = 0;
5417
+ break;
5418
+ }
5419
+ // debug
5420
+ // $this->errmsg = 'X '.$dest_x.' Y '.$dest_y;
5421
+ // $this->showErrorImage();
5422
+ // if a gif, we have to upsample it to a truecolor image
5423
+ if ($this->format == 'GIF') {
5424
+ $tempimage = imagecreatetruecolor($sourcefile_width, $sourcefile_height);
5425
+ imagecopy($tempimage, $this->oldImage, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height);
5426
+ $this->newImage = $tempimage;
5427
+ }
5428
+ $this->imagecopymerge_alpha($this->newImage, $this->workingImage, $dest_x, $dest_y, 0, 0, $watermarkfile_width, $watermarkfile_height, 100);
5429
  }
5430
  /**
5431
+ * Wrapper to imagecopymerge() that allows PNG transparency
 
 
5432
  */
5433
+ function imagecopymerge_alpha($destination_image, $source_image, $destination_x, $destination_y, $source_x, $source_y, $source_w, $source_h, $pct)
5434
  {
5435
+ $cut = imagecreatetruecolor($source_w, $source_h);
5436
+ imagecopy($cut, $destination_image, 0, 0, $destination_x, $destination_y, $source_w, $source_h);
5437
+ imagecopy($cut, $source_image, 0, 0, $source_x, $source_y, $source_w, $source_h);
5438
+ imagecopymerge($destination_image, $cut, $destination_x, $destination_y, 0, 0, $source_w, $source_h, $pct);
 
 
 
 
5439
  }
5440
  /**
5441
+ * Modfied imagecopyresampled function to save transparent images
5442
+ * See : http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/
5443
+ * @since 1.9.0
5444
+ *
5445
+ * @param resource $dst_image
5446
+ * @param resource $src_image
5447
+ * @param int $dst_x
5448
+ * @param int $dst_y
5449
+ * @param int $src_x
5450
+ * @param int $src_y
5451
+ * @param int $dst_w
5452
+ * @param int $dst_h
5453
+ * @param int $src_w
5454
+ * @param int $src_h
5455
+ * @return bool
5456
  */
5457
+ function imagecopyresampled(&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
5458
  {
5459
+ // Check if this image is PNG or GIF, then set if Transparent
5460
+ if ($this->format == 'GIF' || $this->format == 'PNG') {
5461
+ imagealphablending($dst_image, false);
5462
+ imagesavealpha($dst_image, true);
5463
+ $transparent = imagecolorallocatealpha($dst_image, 255, 255, 255, 127);
5464
+ imagefilledrectangle($dst_image, 0, 0, $dst_w, $dst_h, $transparent);
 
 
 
 
 
 
5465
  }
5466
+ imagecopyresampled($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
5467
+ return true;
5468
  }
5469
  }
5470
  /**
5471
+ * Provides methods to C_Gallery_Storage related to dynamic images, thumbnails, clones, etc
5472
  * @property C_Gallery_Storage $object
5473
  */
5474
+ class Mixin_GalleryStorage_Base_Dynamic extends Mixin
5475
  {
5476
  /**
5477
+ * Generates a specific size for an image
5478
+ * @param int|object|C_Image $image
5479
+ * @param string $size
5480
+ * @param array|null $params (optional)
5481
+ * @param bool $skip_defaults (optional)
5482
+ * @return bool|object
5483
  */
5484
+ function generate_image_size($image, $size, $params = null, $skip_defaults = false)
5485
  {
5486
+ $retval = FALSE;
5487
+ // Get the image entity
5488
+ if (is_numeric($image)) {
5489
+ $image = $this->object->_image_mapper->find($image);
5490
  }
5491
+ // Ensure we have a valid image
5492
+ if ($image) {
5493
+ $params = $this->object->get_image_size_params($image, $size, $params, $skip_defaults);
5494
+ $settings = C_NextGen_Settings::get_instance();
5495
+ // Get the image filename
5496
+ $filename = $this->object->get_image_abspath($image, 'original');
5497
+ $thumbnail = null;
5498
+ if ($size == 'full' && $settings->imgBackup == 1) {
5499
+ // XXX change this? 'full' should be the resized path and 'original' the _backup path
5500
+ $backup_path = $this->object->get_backup_abspath($image);
5501
+ if (!@file_exists($backup_path)) {
5502
+ @copy($filename, $backup_path);
5503
+ }
5504
  }
5505
+ // Generate the thumbnail using WordPress
5506
+ $existing_image_abpath = $this->object->get_image_abspath($image, $size);
5507
+ $existing_image_dir = dirname($existing_image_abpath);
5508
+ wp_mkdir_p($existing_image_dir);
5509
+ $clone_path = $existing_image_abpath;
5510
+ $thumbnail = $this->object->generate_image_clone($filename, $clone_path, $params);
5511
+ // We successfully generated the thumbnail
5512
+ if ($thumbnail != null) {
5513
+ $clone_path = $thumbnail->fileName;
5514
+ if (function_exists('getimagesize')) {
5515
+ $dimensions = getimagesize($clone_path);
5516
  } else {
5517
+ $dimensions = array($params['width'], $params['height']);
 
 
5518
  }
5519
+ if (!isset($image->meta_data)) {
5520
+ $image->meta_data = array();
 
 
 
 
 
 
 
 
 
 
 
5521
  }
5522
+ $size_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'filename' => M_I18n::mb_basename($clone_path), 'generated' => microtime());
5523
+ if (isset($params['crop_frame'])) {
5524
+ $size_meta['crop_frame'] = $params['crop_frame'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5525
  }
5526
+ $image->meta_data[$size] = $size_meta;
5527
+ if ($size == 'full') {
5528
+ $image->meta_data['width'] = $size_meta['width'];
5529
+ $image->meta_data['height'] = $size_meta['height'];
5530
+ }
5531
+ $retval = $this->object->_image_mapper->save($image);
5532
+ do_action('ngg_generated_image', $image, $size, $params);
5533
+ if ($retval == 0) {
5534
+ $retval = false;
5535
+ }
5536
+ if ($retval) {
5537
+ $retval = $thumbnail;
5538
+ }
5539
+ } else {
5540
+ // Something went wrong. Thumbnail generation failed!
5541
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5542
  }
5543
  return $retval;
5544
  }
5545
  /**
5546
+ * Generates a thumbnail for an image
5547
+ * @param int|stdClass|C_Image $image
5548
  * @return bool
5549
  */
5550
+ function generate_thumbnail($image, $params = null, $skip_defaults = false)
5551
  {
5552
+ $sized_image = $this->object->generate_image_size($image, 'thumbnail', $params, $skip_defaults);
5553
+ $retval = false;
5554
+ if ($sized_image != null) {
5555
+ $retval = true;
5556
+ $sized_image->destruct();
 
 
 
 
 
 
 
 
 
 
5557
  }
5558
  return $retval;
5559
  }
5560
+ }
5561
+ /**
5562
+ * Provides getter methods to C_Gallery_Storage for determining absolute paths, URL, etc
5563
+ * @property C_Gallery_Storage $object
5564
+ */
5565
+ class Mixin_GalleryStorage_Base_Getters extends Mixin
5566
+ {
5567
+ static $image_abspath_cache = array();
5568
+ static $image_url_cache = array();
5569
+ /**
5570
+ * Gets the absolute path of the backup of an original image
5571
+ * @param string $image
5572
+ * @return null|string
5573
+ */
5574
+ function get_backup_abspath($image)
5575
  {
5576
+ $retval = null;
5577
+ if ($image_path = $this->object->get_image_abspath($image)) {
5578
+ $retval = $image_path . '_backup';
 
 
 
 
 
 
 
 
 
 
 
 
5579
  }
5580
  return $retval;
5581
  }
5582
+ function get_backup_dimensions($image)
5583
  {
5584
+ return $this->object->get_image_dimensions($image, 'backup');
 
 
 
 
 
 
 
 
5585
  }
5586
+ function get_backup_url($image)
5587
  {
5588
+ return $this->object->get_image_url($image, 'backup');
 
 
 
 
 
 
 
 
 
 
 
 
5589
  }
5590
+ /**
5591
+ * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image.
5592
+ * @param int|object $image
5593
+ * @param string $size (optional) Default = full
5594
+ * @param bool $check_existance (optional) Default = false
5595
+ * @return string
5596
+ */
5597
+ function get_image_abspath($image, $size = 'full', $check_existance = FALSE)
5598
  {
5599
+ $image_id = is_numeric($image) ? $image : $image->pid;
5600
+ $size = $this->object->normalize_image_size_name($size);
5601
+ $key = strval($image_id) . $size;
5602
+ if ($check_existance || !isset(self::$image_abspath_cache[$key])) {
5603
+ $retval = $this->object->_get_computed_image_abspath($image, $size, $check_existance);
5604
+ self::$image_abspath_cache[$key] = $retval;
5605
  }
5606
+ $retval = self::$image_abspath_cache[$key];
5607
+ return $retval;
5608
  }
5609
+ /**
5610
+ * Gets the url of a particular-sized image
5611
+ * @param int|object $image
5612
+ * @param string $size
5613
+ * @return string
5614
+ */
5615
+ function get_image_url($image, $size = 'full')
5616
  {
5617
+ $retval = NULL;
5618
+ $image_id = is_numeric($image) ? $image : $image->pid;
5619
+ $key = strval($image_id) . $size;
5620
+ $success = TRUE;
5621
+ if (!isset(self::$image_url_cache[$key])) {
5622
+ $url = $this->object->_get_computed_image_url($image, $size);
5623
+ if ($url) {
5624
+ self::$image_url_cache[$key] = $url;
5625
+ $success = TRUE;
5626
+ } else {
5627
+ $success = FALSE;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5628
  }
5629
+ }
5630
+ if ($success) {
5631
+ $retval = self::$image_url_cache[$key];
 
 
 
 
5632
  } else {
5633
+ $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance();
5634
+ if ($dynthumbs->is_size_dynamic($size)) {
5635
+ $params = $dynthumbs->get_params_from_name($size);
5636
+ $retval = $dynthumbs->get_image_url($image, $params);
5637
+ }
5638
  }
5639
+ return apply_filters('ngg_get_image_url', $retval, $image, $size);
5640
+ }
5641
+ /**
5642
+ * An alias for get_full_abspath()
5643
+ * @param int|object $image
5644
+ * @param bool $check_existance
5645
+ * @return null|string
5646
+ */
5647
+ function get_original_abspath($image, $check_existance = FALSE)
5648
+ {
5649
+ return $this->object->get_image_abspath($image, 'full', $check_existance);
5650
  }
5651
  /**
5652
+ * Flushes the cache we use for path/url calculation for images
 
 
 
 
 
 
5653
  */
5654
+ function flush_image_path_cache($image, $size)
5655
  {
5656
+ $image = is_numeric($image) ? $image : $image->pid;
5657
+ $key = strval($image) . $size;
5658
+ unset(self::$image_abspath_cache[$key]);
5659
+ unset(self::$image_url_cache[$key]);
 
 
 
 
 
 
5660
  }
5661
+ }
5662
+ /**
5663
+ * Provides the basic methods of gallery management to C_Gallery_Storage
5664
+ * @property C_Gallery_Storage $object
5665
+ */
5666
+ class Mixin_GalleryStorage_Base_Management extends Mixin
5667
+ {
5668
  /**
5669
+ * Backs up an image file
5670
+ *
5671
+ * @param int|object $image
5672
+ * @param bool $save
5673
+ * @return bool
5674
  */
5675
+ function backup_image($image, $save = TRUE)
5676
  {
5677
+ $retval = FALSE;
5678
+ $image_path = $this->object->get_image_abspath($image);
5679
+ if ($image_path && @file_exists($image_path)) {
5680
+ $retval = copy($image_path, $this->object->get_backup_abspath($image));
5681
+ // Store the dimensions of the image
5682
+ if (function_exists('getimagesize')) {
5683
+ $mapper = C_Image_Mapper::get_instance();
5684
+ if (!is_object($image)) {
5685
+ $image = $mapper->find($image);
5686
+ }
5687
+ if ($image) {
5688
+ if (!property_exists($image, 'meta_data')) {
5689
+ $image->meta_data = array();
5690
+ }
5691
+ $dimensions = getimagesize($image_path);
5692
+ $image->meta_data['backup'] = array('filename' => basename($image_path), 'width' => $dimensions[0], 'height' => $dimensions[1], 'generated' => microtime());
5693
+ if ($save) {
5694
+ $mapper->save($image);
 
 
 
 
 
5695
  }
 
5696
  }
5697
  }
 
 
 
 
5698
  }
5699
  return $retval;
5700
  }
5701
+ }
5702
+ /**
5703
+ * Provides upload-related methods used by C_Gallery_Storage
5704
+ * @property C_Gallery_Storage $object
5705
+ */
5706
+ class Mixin_GalleryStorage_Base_Upload extends Mixin
5707
+ {
5708
  /**
5709
+ * @param string $abspath
5710
  * @param int $gallery_id
5711
+ * @param bool $create_new_gallerypath
5712
+ * @param null|string $gallery_title
5713
+ * @param array[string] $filenames
5714
+ * @return array|bool FALSE on failure
5715
  */
5716
+ function import_gallery_from_fs($abspath, $gallery_id = NULL, $create_new_gallerypath = TRUE, $gallery_title = NULL, $filenames = array())
5717
  {
5718
+ if (@(!file_exists($abspath))) {
5719
  return FALSE;
5720
  }
 
 
 
 
 
5721
  $fs = C_Fs::get_instance();
5722
+ $retval = array('image_ids' => array());
5723
+ // Ensure that this folder has images
5724
+ $files = array();
5725
+ $directories = array();
5726
+ foreach (scandir($abspath) as $file) {
5727
+ if ($file == '.' || $file == '..' || strtoupper($file) == '__MACOSX') {
5728
+ continue;
5729
+ }
5730
+ $file_abspath = $fs->join_paths($abspath, $file);
5731
+ // Omit 'hidden' directories prefixed with a period
5732
+ if (is_dir($file_abspath) && strpos($file, '.') !== 0) {
5733
+ $directories[] = $file_abspath;
5734
+ } elseif ($this->is_image_file($file_abspath)) {
5735
+ if ($filenames && array_search($file_abspath, $filenames) !== FALSE) {
5736
+ $files[] = $file_abspath;
5737
+ } else {
5738
+ if (!$filenames) {
5739
+ $files[] = $file_abspath;
5740
+ }
5741
+ }
 
 
5742
  }
5743
  }
5744
+ if (empty($files) && empty($directories)) {
5745
+ return FALSE;
 
 
 
 
 
 
 
 
 
5746
  }
5747
+ // Get needed utilities
5748
+ $gallery_mapper = C_Gallery_Mapper::get_instance();
5749
+ // Recurse through the directory and pull in all of the valid images we find
5750
+ if (!empty($directories)) {
5751
+ foreach ($directories as $dir) {
5752
+ $subImport = $this->object->import_gallery_from_fs($dir, $gallery_id, $create_new_gallerypath, $gallery_title, $filenames);
5753
+ if ($subImport) {
5754
+ $retval['image_ids'] = array_merge($retval['image_ids'], $subImport['image_ids']);
5755
+ }
5756
+ }
5757
  }
5758
+ // If no gallery has been specified, then use the directory name as the gallery name
5759
+ if (!$gallery_id) {
5760
+ // Create the gallery
5761
+ $gallery = $gallery_mapper->create(array('title' => $gallery_title ? $gallery_title : M_I18n::mb_basename($abspath)));
5762
+ if (!$create_new_gallerypath) {
5763
+ $gallery_root = $fs->get_document_root('gallery');
5764
+ $gallery->path = str_ireplace($gallery_root, '', $abspath);
 
 
 
 
 
 
 
5765
  }
5766
+ // Save the gallery
5767
+ if ($gallery->save()) {
5768
+ $gallery_id = $gallery->id();
 
 
 
5769
  }
5770
+ }
5771
+ // Ensure that we have a gallery id
5772
+ if (!$gallery_id) {
5773
+ return FALSE;
5774
  } else {
5775
+ $retval['gallery_id'] = $gallery_id;
5776
+ }
5777
+ // Remove full sized image if backup is included
5778
+ $files_to_import = [];
5779
+ foreach ($files as $file_abspath) {
5780
+ if (preg_match("#_backup\$#", $file_abspath)) {
5781
+ $files_to_import[] = $file_abspath;
5782
+ continue;
5783
+ } elseif (in_array($file_abspath . "_backup", $files) || strpos("thumbs_", $file_abspath) !== FALSE) {
5784
+ continue;
 
 
5785
  }
5786
+ $files_to_import[] = $file_abspath;
5787
+ }
5788
+ foreach ($files_to_import as $file_abspath) {
5789
+ $basename = preg_replace('#_backup$#', '', pathinfo($file_abspath, PATHINFO_BASENAME));
5790
+ if ($this->is_image_file($file_abspath)) {
5791
+ if ($image_id = $this->import_image_file($gallery_id, $file_abspath, $basename, FALSE, FALSE, FALSE)) {
5792
+ $retval['image_ids'][] = $image_id;
5793
+ }
5794
  }
5795
  }
5796
+ // Add the gallery name to the result
5797
+ if (!isset($gallery)) {
5798
+ $gallery = $gallery_mapper->find($gallery_id);
5799
+ }
5800
+ $retval['gallery_name'] = $gallery->title;
5801
+ return $retval;
5802
  }
5803
  }
5804
  /**
products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php CHANGED
@@ -163,7 +163,6 @@ class A_Gallery_Display_View extends Mixin
163
  * - title (NextGEN Basic Thumbnails)
164
  * - aliases [basic_thumbnail, basic_thumbnails]
165
  *
166
- * @mixin Mixin_Display_Type_Validation
167
  * @mixin Mixin_Display_Type_Instance_Methods
168
  * @implements I_Display_Type
169
  */
@@ -174,7 +173,6 @@ class C_Display_Type extends C_DataMapper_Model
174
  function define($properties = array(), $mapper = FALSE, $context = FALSE)
175
  {
176
  parent::define($mapper, $properties, $context);
177
- $this->add_mixin('Mixin_Display_Type_Validation');
178
  $this->add_mixin('Mixin_Display_Type_Instance_Methods');
179
  $this->implement('I_Display_Type');
180
  }
@@ -230,16 +228,6 @@ class C_Display_Type extends C_DataMapper_Model
230
  return isset($this->_stdObject->settings[$property_name]) || parent::__isset($property_name);
231
  }
232
  }
233
- class Mixin_Display_Type_Validation extends Mixin
234
- {
235
- function validation()
236
- {
237
- $this->object->validates_presence_of('entity_types');
238
- $this->object->validates_presence_of('name');
239
- $this->object->validates_presence_of('title');
240
- return $this->object->is_valid();
241
- }
242
- }
243
  /**
244
  * Provides methods available for class instances
245
  */
@@ -258,6 +246,13 @@ class Mixin_Display_Type_Instance_Methods extends Mixin
258
  {
259
  return NGG_DISPLAY_PRIORITY_BASE;
260
  }
 
 
 
 
 
 
 
261
  }
262
  /**
263
  * A Controller which displays the settings form for the display type, as
@@ -656,12 +651,6 @@ class C_Display_Type_Mapper extends C_CustomPost_DataMapper_Driver
656
  }
657
  return self::$_instances[$context];
658
  }
659
- }
660
- /**
661
- * Provides instance methods for the display type mapper
662
- */
663
- class Mixin_Display_Type_Mapper extends Mixin
664
- {
665
  /**
666
  * Locates a Display Type by names
667
  * @param string $name
@@ -706,6 +695,12 @@ class Mixin_Display_Type_Mapper extends Mixin
706
  }
707
  return $retval;
708
  }
 
 
 
 
 
 
709
  /**
710
  * Uses the title attribute as the post title
711
  * @param stdClass $entity
@@ -748,20 +743,22 @@ class Mixin_Display_Type_Mapper extends Mixin
748
  * - order_by
749
  * - order_direction
750
  *
751
- * @mixin Mixin_Displayed_Gallery_Validation
752
  * @mixin Mixin_Displayed_Gallery_Instance_Methods
753
- * @mixin Mixin_Displayed_Gallery_Queries
754
  * @implements I_Displayed_Gallery
755
  */
756
  class C_Displayed_Gallery extends C_DataMapper_Model
757
  {
758
  var $_mapper_interface = 'I_Displayed_Gallery_Mapper';
 
 
 
 
 
 
759
  function define($properties = array(), $mapper = FALSE, $context = FALSE)
760
  {
761
  parent::define($mapper, $properties, $context);
762
- $this->add_mixin('Mixin_Displayed_Gallery_Validation');
763
  $this->add_mixin('Mixin_Displayed_Gallery_Instance_Methods');
764
- $this->add_mixin('Mixin_Displayed_Gallery_Queries');
765
  $this->implement('I_Displayed_Gallery');
766
  }
767
  /**
@@ -777,62 +774,6 @@ class C_Displayed_Gallery extends C_DataMapper_Model
777
  }
778
  parent::initialize($mapper, $properties);
779
  }
780
- }
781
- /**
782
- * Provides validation
783
- */
784
- class Mixin_Displayed_Gallery_Validation extends Mixin
785
- {
786
- function validation()
787
- {
788
- // Valid sources
789
- $this->object->validates_presence_of('source');
790
- // Valid display type?
791
- $this->object->validates_presence_of('display_type');
792
- if ($display_type = $this->object->get_display_type()) {
793
- foreach ($this->object->display_settings as $key => $val) {
794
- $display_type->settings[$key] = $val;
795
- }
796
- $this->object->display_settings = $display_type->settings;
797
- if (!$display_type->validate()) {
798
- foreach ($display_type->get_errors() as $property => $errors) {
799
- foreach ($errors as $error) {
800
- $this->object->add_error($error, $property);
801
- }
802
- }
803
- }
804
- $this->object->display_type = $display_type->name;
805
- // Is the display type compatible with the source? E.g., if we're
806
- // using a display type that expects images, we can't be feeding it
807
- // galleries and albums
808
- if ($source = $this->object->get_source()) {
809
- if (!$display_type->is_compatible_with_source($source)) {
810
- $this->object->add_error(__('Source not compatible with selected display type', 'nggallery'), 'display_type');
811
- }
812
- }
813
- // Only some sources should have their own maximum_entity_count
814
- if (!empty($this->object->display_settings['maximum_entity_count']) && in_array($this->object->source, array('tag', 'tags', 'random_images', 'recent_images', 'random', 'recent'))) {
815
- $this->object->maximum_entity_count = $this->object->display_settings['maximum_entity_count'];
816
- }
817
- // If no maximum_entity_count has been given, then set a maximum
818
- if (!isset($this->object->maximum_entity_count)) {
819
- $settings = C_NextGen_Settings::get_instance();
820
- $this->object->maximum_entity_count = $settings->get('maximum_entity_count', 500);
821
- }
822
- } else {
823
- $this->object->add_error('Invalid display type', 'display_type');
824
- }
825
- return $this->object->is_valid();
826
- }
827
- }
828
- class Mixin_Displayed_Gallery_Queries extends Mixin
829
- {
830
- // The "alternative" approach to using "ORDER BY RAND()" works by finding X image PID in a kind of shotgun-blast
831
- // like scattering in a second query made via $wpdb that is then fed into the query built by _get_image_entities().
832
- // This variable is used to cache the results of that inner quasi-random PID retrieval so that multiple calls
833
- // to $displayed_gallery->get_entities() don't return different results for each invocation. This is important
834
- // for NextGen Pro's galleria module in order to 'localize' the results of get_entities() to JSON.
835
- protected static $_random_image_ids_cache = array();
836
  function get_entities($limit = FALSE, $offset = FALSE, $id_only = FALSE, $returns = 'included')
837
  {
838
  $retval = array();
@@ -1074,6 +1015,16 @@ class Mixin_Displayed_Gallery_Queries extends Mixin
1074
  }
1075
  }
1076
  $results = $mapper->run_query();
 
 
 
 
 
 
 
 
 
 
1077
  return $results;
1078
  }
1079
  /**
@@ -1424,38 +1375,6 @@ class Mixin_Displayed_Gallery_Queries extends Mixin
1424
  }
1425
  return strcmp($a->{$key}, $b->{$key});
1426
  }
1427
- }
1428
- /**
1429
- * Provides instance methods useful for working with the C_Displayed_Gallery
1430
- * model
1431
- */
1432
- class Mixin_Displayed_Gallery_Instance_Methods extends Mixin
1433
- {
1434
- function get_entity()
1435
- {
1436
- $entity = $this->call_parent('get_entity');
1437
- unset($entity->post_author);
1438
- unset($entity->post_date);
1439
- unset($entity->post_date_gmt);
1440
- unset($entity->post_title);
1441
- unset($entity->post_excerpt);
1442
- unset($entity->post_status);
1443
- unset($entity->comment_status);
1444
- unset($entity->ping_status);
1445
- unset($entity->post_name);
1446
- unset($entity->to_ping);
1447
- unset($entity->pinged);
1448
- unset($entity->post_modified);
1449
- unset($entity->post_modified_gmt);
1450
- unset($entity->post_parent);
1451
- unset($entity->guid);
1452
- unset($entity->post_type);
1453
- unset($entity->post_mime_type);
1454
- unset($entity->comment_count);
1455
- unset($entity->filter);
1456
- unset($entity->post_content_filtered);
1457
- return $entity;
1458
- }
1459
  /**
1460
  * Gets the display type object used in this displayed gallery
1461
  * @return C_Display_Type
@@ -1464,34 +1383,6 @@ class Mixin_Displayed_Gallery_Instance_Methods extends Mixin
1464
  {
1465
  return C_Display_Type_Mapper::get_instance()->find_by_name($this->object->display_type, TRUE);
1466
  }
1467
- /**
1468
- * Gets the corresponding source instance
1469
- * @return stdClass
1470
- */
1471
- function get_source()
1472
- {
1473
- return C_Displayed_Gallery_Source_Manager::get_instance()->get($this->object->source);
1474
- }
1475
- /**
1476
- * Returns the galleries queries in this displayed gallery
1477
- * @return array
1478
- */
1479
- function get_galleries()
1480
- {
1481
- $retval = array();
1482
- if ($source = $this->object->get_source()) {
1483
- if (in_array('image', $source->returns)) {
1484
- $mapper = C_Gallery_Mapper::get_instance();
1485
- $gallery_key = $mapper->get_primary_key_column();
1486
- $mapper->select();
1487
- if ($this->object->container_ids) {
1488
- $mapper->where(array("{$gallery_key} IN %s", $this->object->container_ids));
1489
- }
1490
- $retval = $mapper->run_query();
1491
- }
1492
- }
1493
- return $retval;
1494
- }
1495
  /**
1496
  * Gets albums queried in this displayed gallery
1497
  * @return array
@@ -1581,8 +1472,109 @@ class Mixin_Displayed_Gallery_Instance_Methods extends Mixin
1581
  return $retval;
1582
  }
1583
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1584
  /**
1585
  * Class C_Displayed_Gallery_Mapper
 
1586
  * @mixin Mixin_Displayed_Gallery_Defaults
1587
  * @implements I_Displayed_Gallery_Mapper
1588
  */
@@ -1620,12 +1612,6 @@ class C_Displayed_Gallery_Mapper extends C_CustomPost_DataMapper_Driver
1620
  }
1621
  return self::$_instances[$context];
1622
  }
1623
- }
1624
- /**
1625
- * Adds default values for the displayed gallery
1626
- */
1627
- class Mixin_Displayed_Gallery_Defaults extends Mixin
1628
- {
1629
  /**
1630
  * Gets a display type object for a particular entity
1631
  * @param stdClass|C_DataMapper_Model $entity
@@ -1636,6 +1622,12 @@ class Mixin_Displayed_Gallery_Defaults extends Mixin
1636
  $mapper = C_Display_Type_Mapper::get_instance();
1637
  return $mapper->find_by_name($entity->display_type);
1638
  }
 
 
 
 
 
 
1639
  /**
1640
  * Sets defaults needed for the entity
1641
  * @param object $entity
@@ -1678,6 +1670,7 @@ class Mixin_Displayed_Gallery_Defaults extends Mixin
1678
  class C_Displayed_Gallery_Renderer extends C_Component
1679
  {
1680
  static $_instances = array();
 
1681
  /**
1682
  * Returns an instance of the class
1683
  * @param bool|string $context
@@ -1701,13 +1694,6 @@ class C_Displayed_Gallery_Renderer extends C_Component
1701
  $this->add_mixin('Mixin_Displayed_Gallery_Renderer');
1702
  $this->implement('I_Displayed_Gallery_Renderer');
1703
  }
1704
- }
1705
- /**
1706
- * Provides the ability to render a display type
1707
- */
1708
- class Mixin_Displayed_Gallery_Renderer extends Mixin
1709
- {
1710
- static $_cache = array();
1711
  function params_to_displayed_gallery($params)
1712
  {
1713
  $hash = crc32(serialize($params));
@@ -1862,7 +1848,6 @@ class Mixin_Displayed_Gallery_Renderer extends Mixin
1862
  */
1863
  function display_images($params_or_dg, $inner_content = NULL, $mode = NULL)
1864
  {
1865
- $retval = '';
1866
  // Convert the array of parameters into a displayed gallery
1867
  if (is_array($params_or_dg)) {
1868
  $params = $params_or_dg;
@@ -1917,6 +1902,19 @@ class Mixin_Displayed_Gallery_Renderer extends Mixin
1917
  }
1918
  return $retval;
1919
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
1920
  /**
1921
  * Renders a displayed gallery on the frontend
1922
  * @param C_Displayed_Gallery $displayed_gallery
@@ -2016,13 +2014,6 @@ class Mixin_Displayed_Gallery_Renderer extends Mixin
2016
  }
2017
  return $retval;
2018
  }
2019
- /**
2020
- * @return bool
2021
- */
2022
- function is_rest_request()
2023
- {
2024
- return defined('REST_REQUEST') || strpos($_SERVER['REQUEST_URI'], 'wp-json') !== FALSE;
2025
- }
2026
  function do_app_rewrites($displayed_gallery)
2027
  {
2028
  }
163
  * - title (NextGEN Basic Thumbnails)
164
  * - aliases [basic_thumbnail, basic_thumbnails]
165
  *
 
166
  * @mixin Mixin_Display_Type_Instance_Methods
167
  * @implements I_Display_Type
168
  */
173
  function define($properties = array(), $mapper = FALSE, $context = FALSE)
174
  {
175
  parent::define($mapper, $properties, $context);
 
176
  $this->add_mixin('Mixin_Display_Type_Instance_Methods');
177
  $this->implement('I_Display_Type');
178
  }
228
  return isset($this->_stdObject->settings[$property_name]) || parent::__isset($property_name);
229
  }
230
  }
 
 
 
 
 
 
 
 
 
 
231
  /**
232
  * Provides methods available for class instances
233
  */
246
  {
247
  return NGG_DISPLAY_PRIORITY_BASE;
248
  }
249
+ function validation()
250
+ {
251
+ $this->object->validates_presence_of('entity_types');
252
+ $this->object->validates_presence_of('name');
253
+ $this->object->validates_presence_of('title');
254
+ return $this->object->is_valid();
255
+ }
256
  }
257
  /**
258
  * A Controller which displays the settings form for the display type, as
651
  }
652
  return self::$_instances[$context];
653
  }
 
 
 
 
 
 
654
  /**
655
  * Locates a Display Type by names
656
  * @param string $name
695
  }
696
  return $retval;
697
  }
698
+ }
699
+ /**
700
+ * Provides instance methods for the display type mapper
701
+ */
702
+ class Mixin_Display_Type_Mapper extends Mixin
703
+ {
704
  /**
705
  * Uses the title attribute as the post title
706
  * @param stdClass $entity
743
  * - order_by
744
  * - order_direction
745
  *
 
746
  * @mixin Mixin_Displayed_Gallery_Instance_Methods
 
747
  * @implements I_Displayed_Gallery
748
  */
749
  class C_Displayed_Gallery extends C_DataMapper_Model
750
  {
751
  var $_mapper_interface = 'I_Displayed_Gallery_Mapper';
752
+ // The "alternative" approach to using "ORDER BY RAND()" works by finding X image PID in a kind of shotgun-blast
753
+ // like scattering in a second query made via $wpdb that is then fed into the query built by _get_image_entities().
754
+ // This variable is used to cache the results of that inner quasi-random PID retrieval so that multiple calls
755
+ // to $displayed_gallery->get_entities() don't return different results for each invocation. This is important
756
+ // for NextGen Pro's galleria module in order to 'localize' the results of get_entities() to JSON.
757
+ protected static $_random_image_ids_cache = array();
758
  function define($properties = array(), $mapper = FALSE, $context = FALSE)
759
  {
760
  parent::define($mapper, $properties, $context);
 
761
  $this->add_mixin('Mixin_Displayed_Gallery_Instance_Methods');
 
762
  $this->implement('I_Displayed_Gallery');
763
  }
764
  /**
774
  }
775
  parent::initialize($mapper, $properties);
776
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
777
  function get_entities($limit = FALSE, $offset = FALSE, $id_only = FALSE, $returns = 'included')
778
  {
779
  $retval = array();
1015
  }
1016
  }
1017
  $results = $mapper->run_query();
1018
+ if (!is_admin() && in_array('image', $source_obj->returns)) {
1019
+ foreach ($results as $entity) {
1020
+ if (!empty($entity->description)) {
1021
+ $entity->description = M_I18N::translate($entity->description, 'pic_' . $entity->pid . '_description');
1022
+ }
1023
+ if (!empty($entity->alttext)) {
1024
+ $entity->alttext = M_I18N::translate($entity->alttext, 'pic_' . $entity->pid . '_alttext');
1025
+ }
1026
+ }
1027
+ }
1028
  return $results;
1029
  }
1030
  /**
1375
  }
1376
  return strcmp($a->{$key}, $b->{$key});
1377
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1378
  /**
1379
  * Gets the display type object used in this displayed gallery
1380
  * @return C_Display_Type
1383
  {
1384
  return C_Display_Type_Mapper::get_instance()->find_by_name($this->object->display_type, TRUE);
1385
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1386
  /**
1387
  * Gets albums queried in this displayed gallery
1388
  * @return array
1472
  return $retval;
1473
  }
1474
  }
1475
+ /**
1476
+ * Provides instance methods useful for working with the C_Displayed_Gallery model
1477
+ */
1478
+ class Mixin_Displayed_Gallery_Instance_Methods extends Mixin
1479
+ {
1480
+ function validation()
1481
+ {
1482
+ // Valid sources
1483
+ $this->object->validates_presence_of('source');
1484
+ // Valid display type?
1485
+ $this->object->validates_presence_of('display_type');
1486
+ if ($display_type = $this->object->get_display_type()) {
1487
+ foreach ($this->object->display_settings as $key => $val) {
1488
+ $display_type->settings[$key] = $val;
1489
+ }
1490
+ $this->object->display_settings = $display_type->settings;
1491
+ if (!$display_type->validate()) {
1492
+ foreach ($display_type->get_errors() as $property => $errors) {
1493
+ foreach ($errors as $error) {
1494
+ $this->object->add_error($error, $property);
1495
+ }
1496
+ }
1497
+ }
1498
+ $this->object->display_type = $display_type->name;
1499
+ // Is the display type compatible with the source? E.g., if we're
1500
+ // using a display type that expects images, we can't be feeding it
1501
+ // galleries and albums
1502
+ if ($source = $this->object->get_source()) {
1503
+ if (!$display_type->is_compatible_with_source($source)) {
1504
+ $this->object->add_error(__('Source not compatible with selected display type', 'nggallery'), 'display_type');
1505
+ }
1506
+ }
1507
+ // Only some sources should have their own maximum_entity_count
1508
+ if (!empty($this->object->display_settings['maximum_entity_count']) && in_array($this->object->source, array('tag', 'tags', 'random_images', 'recent_images', 'random', 'recent'))) {
1509
+ $this->object->maximum_entity_count = $this->object->display_settings['maximum_entity_count'];
1510
+ }
1511
+ // If no maximum_entity_count has been given, then set a maximum
1512
+ if (!isset($this->object->maximum_entity_count)) {
1513
+ $settings = C_NextGen_Settings::get_instance();
1514
+ $this->object->maximum_entity_count = $settings->get('maximum_entity_count', 500);
1515
+ }
1516
+ } else {
1517
+ $this->object->add_error('Invalid display type', 'display_type');
1518
+ }
1519
+ return $this->object->is_valid();
1520
+ }
1521
+ function get_entity()
1522
+ {
1523
+ $entity = $this->call_parent('get_entity');
1524
+ unset($entity->post_author);
1525
+ unset($entity->post_date);
1526
+ unset($entity->post_date_gmt);
1527
+ unset($entity->post_title);
1528
+ unset($entity->post_excerpt);
1529
+ unset($entity->post_status);
1530
+ unset($entity->comment_status);
1531
+ unset($entity->ping_status);
1532
+ unset($entity->post_name);
1533
+ unset($entity->to_ping);
1534
+ unset($entity->pinged);
1535
+ unset($entity->post_modified);
1536
+ unset($entity->post_modified_gmt);
1537
+ unset($entity->post_parent);
1538
+ unset($entity->guid);
1539
+ unset($entity->post_type);
1540
+ unset($entity->post_mime_type);
1541
+ unset($entity->comment_count);
1542
+ unset($entity->filter);
1543
+ unset($entity->post_content_filtered);
1544
+ return $entity;
1545
+ }
1546
+ /**
1547
+ * Gets the corresponding source instance
1548
+ * @return stdClass
1549
+ */
1550
+ function get_source()
1551
+ {
1552
+ return C_Displayed_Gallery_Source_Manager::get_instance()->get($this->object->source);
1553
+ }
1554
+ /**
1555
+ * Returns the galleries queries in this displayed gallery
1556
+ * @return array
1557
+ */
1558
+ function get_galleries()
1559
+ {
1560
+ $retval = array();
1561
+ if ($source = $this->object->get_source()) {
1562
+ if (in_array('image', $source->returns)) {
1563
+ $mapper = C_Gallery_Mapper::get_instance();
1564
+ $gallery_key = $mapper->get_primary_key_column();
1565
+ $mapper->select();
1566
+ if ($this->object->container_ids) {
1567
+ $mapper->where(array("{$gallery_key} IN %s", $this->object->container_ids));
1568
+ }
1569
+ $retval = $mapper->run_query();
1570
+ }
1571
+ }
1572
+ return $retval;
1573
+ }
1574
+ }
1575
  /**
1576
  * Class C_Displayed_Gallery_Mapper
1577
+ *
1578
  * @mixin Mixin_Displayed_Gallery_Defaults
1579
  * @implements I_Displayed_Gallery_Mapper
1580
  */
1612
  }
1613
  return self::$_instances[$context];
1614
  }
 
 
 
 
 
 
1615
  /**
1616
  * Gets a display type object for a particular entity
1617
  * @param stdClass|C_DataMapper_Model $entity
1622
  $mapper = C_Display_Type_Mapper::get_instance();
1623
  return $mapper->find_by_name($entity->display_type);
1624
  }
1625
+ }
1626
+ /**
1627
+ * Adds default values for the displayed gallery
1628
+ */
1629
+ class Mixin_Displayed_Gallery_Defaults extends Mixin
1630
+ {
1631
  /**
1632
  * Sets defaults needed for the entity
1633
  * @param object $entity
1670
  class C_Displayed_Gallery_Renderer extends C_Component
1671
  {
1672
  static $_instances = array();
1673
+ static $_cache = array();
1674
  /**
1675
  * Returns an instance of the class
1676
  * @param bool|string $context
1694
  $this->add_mixin('Mixin_Displayed_Gallery_Renderer');
1695
  $this->implement('I_Displayed_Gallery_Renderer');
1696
  }
 
 
 
 
 
 
 
1697
  function params_to_displayed_gallery($params)
1698
  {
1699
  $hash = crc32(serialize($params));
1848
  */
1849
  function display_images($params_or_dg, $inner_content = NULL, $mode = NULL)
1850
  {
 
1851
  // Convert the array of parameters into a displayed gallery
1852
  if (is_array($params_or_dg)) {
1853
  $params = $params_or_dg;
1902
  }
1903
  return $retval;
1904
  }
1905
+ /**
1906
+ * @return bool
1907
+ */
1908
+ function is_rest_request()
1909
+ {
1910
+ return defined('REST_REQUEST') || strpos($_SERVER['REQUEST_URI'], 'wp-json') !== FALSE;
1911
+ }
1912
+ }
1913
+ /**
1914
+ * Provides the ability to render a display type
1915
+ */
1916
+ class Mixin_Displayed_Gallery_Renderer extends Mixin
1917
+ {
1918
  /**
1919
  * Renders a displayed gallery on the frontend
1920
  * @param C_Displayed_Gallery $displayed_gallery
2014
  }
2015
  return $retval;
2016
  }
 
 
 
 
 
 
 
2017
  function do_app_rewrites($displayed_gallery)
2018
  {
2019
  }
products/photocrati_nextgen/modules/nextgen_other_options/package.module.nextgen_other_options.php CHANGED
@@ -337,7 +337,7 @@ class A_Miscellaneous_Form extends Mixin
337
  }
338
  function render()
339
  {
340
- return $this->object->render_partial('photocrati-nextgen_other_options#misc_tab', array('mediarss_activated' => C_NextGen_Settings::get_instance()->useMediaRSS, 'mediarss_activated_label' => __('Add MediaRSS link?', 'nggallery'), 'mediarss_activated_help' => __('When enabled, adds a MediaRSS link to your header. Third-party web services can use this to publish your galleries', 'nggallery'), 'mediarss_activated_no' => __('No'), 'mediarss_activated_yes' => __('Yes'), 'galleries_in_feeds' => C_NextGen_Settings::get_instance()->galleries_in_feeds, 'galleries_in_feeds_label' => __('Display galleries in feeds', 'nggallery'), 'galleries_in_feeds_help' => __('NextGEN hides its gallery displays in feeds other than MediaRSS. This enables image galleries in feeds.', 'nggallery'), 'galleries_in_feeds_no' => __('No'), 'galleries_in_feeds_yes' => __('Yes'), 'cache_label' => __('Clear image cache', 'nggallery'), 'cache_confirmation' => __("Completely clear the NextGEN cache of all image modifications?\n\nChoose [Cancel] to Stop, [OK] to proceed.", 'nggallery'), 'update_legacy_featured_images_field' => $this->object->render_partial('photocrati-nextgen_other_options#update_legacy_featured_images_field', ['i18n' => ['label' => __('Update legacy page featured images', 'nggallery'), 'confirmation' => __('Continue? This will copy all NextGen 1.x page featured images into the media library.', 'nggallery'), 'tooltip' => __('WordPress 5.4 is incompatible with NextGen 1.x page featured images and they must be updated in a bulk process to correct them. This button will launch a background process (with a progress bar) that imports each NextGen image into the Media Library. This process can be resumed if you close the popup window or this browser window.', 'nggallery'), 'header' => __('Updating legacy page featured images', 'nggallery'), 'no_images_found' => __('No legacy page featured images were found.', 'nggallery'), 'operation_finished' => __('Operation complete. Legacy featured images have been corrected.', 'nggallery')]], TRUE), 'slug_field' => $this->_render_text_field((object) array('name' => 'misc_settings'), 'router_param_slug', __('Permalink slug', 'nggallery'), $this->object->get_model()->router_param_slug), 'maximum_entity_count_field' => $this->_render_number_field((object) array('name' => 'misc_settings'), 'maximum_entity_count', __('Maximum image count', 'nggallery'), $this->object->get_model()->maximum_entity_count, __('This is the maximum limit of images that NextGEN will restrict itself to querying', 'nggallery') . " \n " . __('Note: This limit will not apply to slideshow widgets or random galleries if/when those galleries specify their own image limits', 'nggallery'), FALSE, '', 1), 'random_widget_cache_ttl_field' => $this->_render_number_field((object) array('name' => 'misc_settings'), 'random_widget_cache_ttl', __('Random widget cache duration', 'nggallery'), $this->object->get_model()->random_widget_cache_ttl, __('The duration of time (in minutes) that "random" widget galleries should be cached. A setting of zero will disable caching.', 'nggallery'), FALSE, '', 0), 'alternate_random_method_field' => $this->_render_radio_field((object) array('name' => 'misc_settings'), 'use_alternate_random_method', __('Use alternative method of retrieving random image galleries', 'nggallery'), C_NextGen_Settings::get_instance()->use_alternate_random_method, __("Some web hosts' database servers disable or disrupt queries using 'ORDER BY RAND()' which can cause galleries to lose their randomness. NextGen provides an alternative (but not completely random) method to determine what images are fed into 'random' galleries.", 'nggallery')), 'disable_fontawesome_field' => $this->_render_radio_field((object) array('name' => 'misc_settings'), 'disable_fontawesome', __('Do not enqueue FontAwesome', 'nggallery'), C_NextGen_Settings::get_instance()->disable_fontawesome, __("Warning: your theme or another plugin must provide FontAwesome or your gallery displays may appear incorrectly", 'nggallery')), 'disable_ngg_tags_page_field' => $this->_render_radio_field((object) array('name' => 'misc_settings'), 'disable_ngg_tags_page', __('Disable the /ngg_tag/ page', 'nggallery'), C_NextGen_Settings::get_instance()->get('disable_ngg_tags_page', FALSE), __("Normally an SEO feature; some users may wish to disable this to prevent NextGEN from revealing image tags to site visitors", 'nggallery'))), TRUE);
341
  }
342
  function cache_action()
343
  {
@@ -358,7 +358,7 @@ class A_Miscellaneous_Form extends Mixin
358
  $settings['router_param_slug'] = 'nggallery';
359
  }
360
  // If the router slug has changed, then flush the cache
361
- if ($settings['router_param_slug'] != $this->object->get_model()->router_param_slug) {
362
  C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
363
  }
364
  // Do not allow this field to ever be unset
337
  }
338
  function render()
339
  {
340
+ return $this->object->render_partial('photocrati-nextgen_other_options#misc_tab', array('mediarss_activated' => C_NextGen_Settings::get_instance()->useMediaRSS, 'mediarss_activated_label' => __('Add MediaRSS link?', 'nggallery'), 'mediarss_activated_help' => __('When enabled, adds a MediaRSS link to your header. Third-party web services can use this to publish your galleries', 'nggallery'), 'mediarss_activated_no' => __('No'), 'mediarss_activated_yes' => __('Yes'), 'galleries_in_feeds' => C_NextGen_Settings::get_instance()->galleries_in_feeds, 'galleries_in_feeds_label' => __('Display galleries in feeds', 'nggallery'), 'galleries_in_feeds_help' => __('NextGEN hides its gallery displays in feeds other than MediaRSS. This enables image galleries in feeds.', 'nggallery'), 'galleries_in_feeds_no' => __('No'), 'galleries_in_feeds_yes' => __('Yes'), 'cache_label' => __('Clear image cache', 'nggallery'), 'cache_confirmation' => __("Completely clear the NextGEN cache of all image modifications?\n\nChoose [Cancel] to Stop, [OK] to proceed.", 'nggallery'), 'update_legacy_featured_images_field' => $this->object->render_partial('photocrati-nextgen_other_options#update_legacy_featured_images_field', ['i18n' => ['label' => __('Update legacy page featured images', 'nggallery'), 'confirmation' => __('Continue? This will copy all NextGen 1.x page featured images into the media library.', 'nggallery'), 'tooltip' => __('WordPress 5.4 is incompatible with NextGen 1.x page featured images and they must be updated in a bulk process to correct them. This button will launch a background process (with a progress bar) that imports each NextGen image into the Media Library. This process can be resumed if you close the popup window or this browser window.', 'nggallery'), 'header' => __('Updating legacy page featured images', 'nggallery'), 'no_images_found' => __('No legacy page featured images were found.', 'nggallery'), 'operation_finished' => __('Operation complete. Legacy featured images have been corrected.', 'nggallery')]], TRUE), 'slug_field' => $this->_render_text_field((object) array('name' => 'misc_settings'), 'router_param_slug', __('Permalink slug', 'nggallery'), $this->object->get_model()->get('router_param_slug', 'nggallery')), 'maximum_entity_count_field' => $this->_render_number_field((object) array('name' => 'misc_settings'), 'maximum_entity_count', __('Maximum image count', 'nggallery'), $this->object->get_model()->maximum_entity_count, __('This is the maximum limit of images that NextGEN will restrict itself to querying', 'nggallery') . " \n " . __('Note: This limit will not apply to slideshow widgets or random galleries if/when those galleries specify their own image limits', 'nggallery'), FALSE, '', 1), 'random_widget_cache_ttl_field' => $this->_render_number_field((object) array('name' => 'misc_settings'), 'random_widget_cache_ttl', __('Random widget cache duration', 'nggallery'), $this->object->get_model()->random_widget_cache_ttl, __('The duration of time (in minutes) that "random" widget galleries should be cached. A setting of zero will disable caching.', 'nggallery'), FALSE, '', 0), 'alternate_random_method_field' => $this->_render_radio_field((object) array('name' => 'misc_settings'), 'use_alternate_random_method', __('Use alternative method of retrieving random image galleries', 'nggallery'), C_NextGen_Settings::get_instance()->use_alternate_random_method, __("Some web hosts' database servers disable or disrupt queries using 'ORDER BY RAND()' which can cause galleries to lose their randomness. NextGen provides an alternative (but not completely random) method to determine what images are fed into 'random' galleries.", 'nggallery')), 'disable_fontawesome_field' => $this->_render_radio_field((object) array('name' => 'misc_settings'), 'disable_fontawesome', __('Do not enqueue FontAwesome', 'nggallery'), C_NextGen_Settings::get_instance()->disable_fontawesome, __("Warning: your theme or another plugin must provide FontAwesome or your gallery displays may appear incorrectly", 'nggallery')), 'disable_ngg_tags_page_field' => $this->_render_radio_field((object) array('name' => 'misc_settings'), 'disable_ngg_tags_page', __('Disable the /ngg_tag/ page', 'nggallery'), C_NextGen_Settings::get_instance()->get('disable_ngg_tags_page', FALSE), __("Normally an SEO feature; some users may wish to disable this to prevent NextGEN from revealing image tags to site visitors", 'nggallery'))), TRUE);
341
  }
342
  function cache_action()
343
  {
358
  $settings['router_param_slug'] = 'nggallery';
359
  }
360
  // If the router slug has changed, then flush the cache
361
+ if ($settings['router_param_slug'] != $this->object->get_model()->get('router_param_slug')) {
362
  C_Photocrati_Transient_Manager::flush('displayed_gallery_rendering');
363
  }
364
  // Do not allow this field to ever be unset
products/photocrati_nextgen/modules/ngglegacy/fonts/YanoneKaffeesatz-Bold.ttf CHANGED
File without changes
products/photocrati_nextgen/modules/router/module.router.php CHANGED
@@ -15,7 +15,7 @@ class M_Router extends C_Base_Module
15
  'photocrati-router',
16
  'Router for Pope',
17
  'Provides routing capabilities for Pope modules',
18
- '3.1.7.1',
19
  'https://www.imagely.com',
20
  'Imagely',
21
  'https://www.imagely.com'
15
  'photocrati-router',
16
  'Router for Pope',
17
  'Provides routing capabilities for Pope modules',
18
+ '3.13',
19
  'https://www.imagely.com',
20
  'Imagely',
21
  'https://www.imagely.com'
products/photocrati_nextgen/modules/router/package.module.router.php CHANGED
@@ -1080,9 +1080,9 @@ class C_Routing_App extends C_Component
1080
  {
1081
  $settings = C_NextGen_Settings::get_instance();
1082
  $object = new stdClass();
1083
- $object->router_param_separator = $settings->router_param_separator;
1084
- $object->router_param_slug = $settings->router_param_slug;
1085
- $object->router_param_prefix = $settings->router_param_prefix;
1086
  return $object;
1087
  }
1088
  static function &get_instance($context = False)
@@ -1229,9 +1229,9 @@ class Mixin_Url_Manipulation extends Mixin
1229
  {
1230
  $retval = $request_uri ? $request_uri : '/';
1231
  $settings = C_NextGen_Settings::get_instance();
1232
- $sep = preg_quote($settings->router_param_separator, '#');
1233
  $param_regex = "#((?P<id>\\w+){$sep})?(?<key>\\w+){$sep}(?P<value>.+)/?\$#";
1234
- $slug = $settings->router_param_slug && $remove_slug ? '/' . preg_quote($settings->router_param_slug, '#') : '';
1235
  $slug_regex = '#' . $slug . '/?$#';
1236
  // Remove all parameters
1237
  while (@preg_match($param_regex, $retval, $matches)) {
1080
  {
1081
  $settings = C_NextGen_Settings::get_instance();
1082
  $object = new stdClass();
1083
+ $object->router_param_separator = $settings->get('router_param_separator', '--');
1084
+ $object->router_param_slug = $settings->get('router_param_slug', 'nggallery');
1085
+ $object->router_param_prefix = $settings->get('router_param_prefix', '');
1086
  return $object;
1087
  }
1088
  static function &get_instance($context = False)
1229
  {
1230
  $retval = $request_uri ? $request_uri : '/';
1231
  $settings = C_NextGen_Settings::get_instance();
1232
+ $sep = preg_quote($settings->get('router_param_separator', '--'), '#');
1233
  $param_regex = "#((?P<id>\\w+){$sep})?(?<key>\\w+){$sep}(?P<value>.+)/?\$#";
1234
+ $slug = $settings->get('router_param_slug', 'nggallery') && $remove_slug ? '/' . preg_quote($settings->get('router_param_slug', 'nggallery'), '#') : '';
1235
  $slug_regex = '#' . $slug . '/?$#';
1236
  // Remove all parameters
1237
  while (@preg_match($param_regex, $retval, $matches)) {
products/photocrati_nextgen/modules/security/package.module.security.php CHANGED
@@ -89,38 +89,6 @@ class Mixin_Security_Actor_Entity extends Mixin
89
  return null;
90
  }
91
  }
92
- // XXX not used yet
93
- class Mixin_Security_Entity_List extends Mixin
94
- {
95
- var $_entity_list;
96
- function add_entity($entity, $entity_props = null)
97
- {
98
- if (!$this->object->is_entity($entity)) {
99
- $entity_props = array_merge((array) $entity_props, array('object' => $entity));
100
- $this->object->_entity_list[] = $entity_props;
101
- }
102
- }
103
- function remove_entity($entity)
104
- {
105
- if ($this->object->is_entity($entity)) {
106
- }
107
- }
108
- function is_entity($entity)
109
- {
110
- return $this->object->get_entity_set($entity);
111
- }
112
- function get_entity_set($entity)
113
- {
114
- foreach ($this->_entity_list as $entity_set) {
115
- }
116
- }
117
- function get_entity_id($entity)
118
- {
119
- }
120
- function get_entity_type($entity)
121
- {
122
- }
123
- }
124
  /**
125
  * Class C_Security_Actor
126
  * @mixin Mixin_Security_Actor
89
  return null;
90
  }
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  /**
93
  * Class C_Security_Actor
94
  * @mixin Mixin_Security_Actor
products/photocrati_nextgen/modules/widget/package.module.widget.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  * Class C_Widget
4
- * @mixin Mixin_Widget
5
  * @implements I_Widget
6
  */
7
  class C_Widget extends C_MVC_Controller
@@ -10,7 +10,6 @@ class C_Widget extends C_MVC_Controller
10
  function define($context = FALSE)
11
  {
12
  parent::define($context);
13
- $this->add_mixin('Mixin_Widget');
14
  $this->implement('I_Widget');
15
  }
16
  /**
@@ -24,9 +23,6 @@ class C_Widget extends C_MVC_Controller
24
  }
25
  return self::$_instances[$context];
26
  }
27
- }
28
- class Mixin_Widget extends Mixin
29
- {
30
  /**
31
  * Function for templates without widget support
32
  *
1
  <?php
2
  /**
3
  * Class C_Widget
4
+ *
5
  * @implements I_Widget
6
  */
7
  class C_Widget extends C_MVC_Controller
10
  function define($context = FALSE)
11
  {
12
  parent::define($context);
 
13
  $this->implement('I_Widget');
14
  }
15
  /**
23
  }
24
  return self::$_instances[$context];
25
  }
 
 
 
26
  /**
27
  * Function for templates without widget support
28
  *
products/photocrati_nextgen/modules/wordpress_routing/package.module.wordpress_routing.php CHANGED
@@ -172,7 +172,7 @@ class A_WordPress_Routing_App extends Mixin
172
  $generated_url = $base_url;
173
  }
174
  $original_url = $generated_url;
175
- $generated_parts = explode($settings->router_param_slug, $generated_url);
176
  $generated_url = $generated_parts[0];
177
  $ngg_parameters = '/';
178
  if (isset($generated_parts[1])) {
@@ -219,7 +219,7 @@ class A_WordPress_Routing_App extends Mixin
219
  // The post permalink differs from the generated url
220
  $post_permalink = str_replace(home_url(), $base_url, $post_permalink);
221
  $post_parts = $this->parse_url($post_permalink);
222
- $post_parts['path'] = $this->object->join_paths($post_parts['path'], $settings->router_param_slug, $ngg_parameters);
223
  $post_parts['path'] = str_replace('index.php/index.php', 'index.php', $post_parts['path']);
224
  // incase permalink_structure contains index.php
225
  if (!empty($generated_parts['query']) && empty($post_parts['query'])) {
172
  $generated_url = $base_url;
173
  }
174
  $original_url = $generated_url;
175
+ $generated_parts = explode($settings->get('router_param_slug', 'nggallery'), $generated_url);
176
  $generated_url = $generated_parts[0];
177
  $ngg_parameters = '/';
178
  if (isset($generated_parts[1])) {
219
  // The post permalink differs from the generated url
220
  $post_permalink = str_replace(home_url(), $base_url, $post_permalink);
221
  $post_parts = $this->parse_url($post_permalink);
222
+ $post_parts['path'] = $this->object->join_paths($post_parts['path'], $settings->get('router_param_slug', 'nggallery'), $ngg_parameters);
223
  $post_parts['path'] = str_replace('index.php/index.php', 'index.php', $post_parts['path']);
224
  // incase permalink_structure contains index.php
225
  if (!empty($generated_parts['query']) && empty($post_parts['query'])) {
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: photocrati, imagely
3
  Tags: wordpress gallery plugin, gallery, nextgen, nextgen gallery, photo gallery, image gallery, photography, slideshow, images, photo, photo album, watermark
4
  Requires at least: 5.5.4
5
- Stable tag: 3.12
6
  Tested up to: 5.7.2
7
  License: GPLv3
8
  Requires PHP: 5.6
@@ -179,6 +179,9 @@ For more information, feel free to visit the official website for the NextGEN Ga
179
 
180
  == Changelog ==
181
 
 
 
 
182
  = V3.12 - 07.13.2021
183
  * Fixed: PHP warning generated for some Nimble Builder users
184
  * Changed: Added 'ngg_marketing_parameters' filter
2
  Contributors: photocrati, imagely
3
  Tags: wordpress gallery plugin, gallery, nextgen, nextgen gallery, photo gallery, image gallery, photography, slideshow, images, photo, photo album, watermark
4
  Requires at least: 5.5.4
5
+ Stable tag: 3.13
6
  Tested up to: 5.7.2
7
  License: GPLv3
8
  Requires PHP: 5.6
179
 
180
  == Changelog ==
181
 
182
+ = V3.13 - 08.04.2021
183
+ * Fixed: All WP-Admin links had "/wp-admin/" removed for some users
184
+
185
  = V3.12 - 07.13.2021
186
  * Fixed: PHP warning generated for some Nimble Builder users
187
  * Changed: Added 'ngg_marketing_parameters' filter
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit7bc62a53579d4cf2f168e2a871d0a612::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInitb306934e72249cb9ae140e81b71d2647::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit7bc62a53579d4cf2f168e2a871d0a612
6
  {
7
  private static $loader;
8
 
@@ -24,15 +24,15 @@ class ComposerAutoloaderInit7bc62a53579d4cf2f168e2a871d0a612
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
- spl_autoload_register(array('ComposerAutoloaderInit7bc62a53579d4cf2f168e2a871d0a612', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
29
- spl_autoload_unregister(array('ComposerAutoloaderInit7bc62a53579d4cf2f168e2a871d0a612', 'loadClassLoader'));
30
 
31
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
32
  if ($useStaticLoader) {
33
  require __DIR__ . '/autoload_static.php';
34
 
35
- call_user_func(\Composer\Autoload\ComposerStaticInit7bc62a53579d4cf2f168e2a871d0a612::getInitializer($loader));
36
  } else {
37
  $map = require __DIR__ . '/autoload_namespaces.php';
38
  foreach ($map as $namespace => $path) {
@@ -53,19 +53,19 @@ class ComposerAutoloaderInit7bc62a53579d4cf2f168e2a871d0a612
53
  $loader->register(true);
54
 
55
  if ($useStaticLoader) {
56
- $includeFiles = Composer\Autoload\ComposerStaticInit7bc62a53579d4cf2f168e2a871d0a612::$files;
57
  } else {
58
  $includeFiles = require __DIR__ . '/autoload_files.php';
59
  }
60
  foreach ($includeFiles as $fileIdentifier => $file) {
61
- composerRequire7bc62a53579d4cf2f168e2a871d0a612($fileIdentifier, $file);
62
  }
63
 
64
  return $loader;
65
  }
66
  }
67
 
68
- function composerRequire7bc62a53579d4cf2f168e2a871d0a612($fileIdentifier, $file)
69
  {
70
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
71
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInitb306934e72249cb9ae140e81b71d2647
6
  {
7
  private static $loader;
8
 
24
 
25
  require __DIR__ . '/platform_check.php';
26
 
27
+ spl_autoload_register(array('ComposerAutoloaderInitb306934e72249cb9ae140e81b71d2647', 'loadClassLoader'), true, true);
28
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
29
+ spl_autoload_unregister(array('ComposerAutoloaderInitb306934e72249cb9ae140e81b71d2647', 'loadClassLoader'));
30
 
31
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
32
  if ($useStaticLoader) {
33
  require __DIR__ . '/autoload_static.php';
34
 
35
+ call_user_func(\Composer\Autoload\ComposerStaticInitb306934e72249cb9ae140e81b71d2647::getInitializer($loader));
36
  } else {
37
  $map = require __DIR__ . '/autoload_namespaces.php';
38
  foreach ($map as $namespace => $path) {
53
  $loader->register(true);
54
 
55
  if ($useStaticLoader) {
56
+ $includeFiles = Composer\Autoload\ComposerStaticInitb306934e72249cb9ae140e81b71d2647::$files;
57
  } else {
58
  $includeFiles = require __DIR__ . '/autoload_files.php';
59
  }
60
  foreach ($includeFiles as $fileIdentifier => $file) {
61
+ composerRequireb306934e72249cb9ae140e81b71d2647($fileIdentifier, $file);
62
  }
63
 
64
  return $loader;
65
  }
66
  }
67
 
68
+ function composerRequireb306934e72249cb9ae140e81b71d2647($fileIdentifier, $file)
69
  {
70
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
71
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit7bc62a53579d4cf2f168e2a871d0a612
8
  {
9
  public static $files = array (
10
  '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
@@ -28,8 +28,8 @@ class ComposerStaticInit7bc62a53579d4cf2f168e2a871d0a612
28
  public static function getInitializer(ClassLoader $loader)
29
  {
30
  return \Closure::bind(function () use ($loader) {
31
- $loader->prefixesPsr0 = ComposerStaticInit7bc62a53579d4cf2f168e2a871d0a612::$prefixesPsr0;
32
- $loader->classMap = ComposerStaticInit7bc62a53579d4cf2f168e2a871d0a612::$classMap;
33
 
34
  }, null, ClassLoader::class);
35
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInitb306934e72249cb9ae140e81b71d2647
8
  {
9
  public static $files = array (
10
  '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
28
  public static function getInitializer(ClassLoader $loader)
29
  {
30
  return \Closure::bind(function () use ($loader) {
31
+ $loader->prefixesPsr0 = ComposerStaticInitb306934e72249cb9ae140e81b71d2647::$prefixesPsr0;
32
+ $loader->classMap = ComposerStaticInitb306934e72249cb9ae140e81b71d2647::$classMap;
33
 
34
  }, null, ClassLoader::class);
35
  }
vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README CHANGED
File without changes
vendor/imagely/pope-framework/README.txt CHANGED
File without changes
vendor/imagely/pope-framework/lib/autoload.php CHANGED
File without changes
vendor/imagely/pope-framework/lib/class.base_module.php CHANGED
@@ -90,20 +90,20 @@ abstract class C_Base_Module
90
  */
91
  function get_type_list()
92
  {
93
- // XXX small hack to skip photocrati theme modules scans
94
- $except_modules = array(
95
- 'photocrati-gallery_legacy' => array(),
96
- 'photocrati-theme_bulk' => array(),
97
- 'photocrati-theme_admin' => array(),
98
- 'photocrati-auto_update' => array(
99
- 'A_Autoupdate_Settings' => 'adapter.autoupdate_settings.php'
100
- ),
101
- 'photocrati-auto_update-admin' => array(
102
- 'A_Autoupdate_Admin_Ajax' => 'adapter.autoupdate_admin_ajax.php',
103
- 'A_Autoupdate_Admin_Factory' => 'adapter.autoupdate_admin_factory.php',
104
- 'C_Autoupdate_Admin_Ajax' => 'class.autoupdate_admin_ajax.php',
105
- 'C_Autoupdate_Admin_Controller' => 'class.autoupdate_admin_controller.php'
106
- ));
107
 
108
  if (isset($except_modules[$this->module_id]))
109
  {
90
  */
91
  function get_type_list()
92
  {
93
+ // XXX small hack to skip photocrati theme modules scans
94
+ $except_modules = array(
95
+ 'photocrati-gallery_legacy' => array(),
96
+ 'photocrati-theme_bulk' => array(),
97
+ 'photocrati-theme_admin' => array(),
98
+ 'photocrati-auto_update' => array(
99
+ 'A_Autoupdate_Settings' => 'adapter.autoupdate_settings.php'
100
+ ),
101
+ 'photocrati-auto_update-admin' => array(
102
+ 'A_Autoupdate_Admin_Ajax' => 'adapter.autoupdate_admin_ajax.php',
103
+ 'A_Autoupdate_Admin_Factory' => 'adapter.autoupdate_admin_factory.php',
104
+ 'C_Autoupdate_Admin_Ajax' => 'class.autoupdate_admin_ajax.php',
105
+ 'C_Autoupdate_Admin_Controller' => 'class.autoupdate_admin_controller.php'
106
+ ));
107
 
108
  if (isset($except_modules[$this->module_id]))
109
  {
vendor/imagely/pope-framework/lib/class.base_product.php CHANGED
File without changes
vendor/imagely/pope-framework/lib/class.component.php CHANGED
File without changes
vendor/imagely/pope-framework/lib/class.component_factory.php CHANGED
File without changes
vendor/imagely/pope-framework/lib/class.component_registry.php CHANGED
@@ -793,38 +793,41 @@ class C_Component_Registry
793
  $recursive_level++;
794
 
795
  $abspath = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $abspath);
796
- if (!in_array($abspath, $exclusions)) {
 
797
  $contents = @scandir($abspath);
798
- if ($contents) foreach ($contents as $filename) {
799
- if (in_array($filename, $exclusions)) continue;
800
- $filename_abspath = $abspath.DIRECTORY_SEPARATOR.$filename;
801
-
802
- // Is this a subdirectory?
803
- // We don't use is_dir(), as it's less efficient than just checking for a 'dot' in the filename.
804
- // The problem is that we're assuming that our directories won't contain a 'dot'.
805
- if ($recursive && strpos($filename, '.') === FALSE) {
806
-
807
- // The recursive parameter can either be set to TRUE or the number of levels to navigate
808
- // If we reach the max number of recursive levels we're supported to navigate, then we try
809
- // to guess if there's a module or product file under the directory with the same name as
810
- // the directory
811
- if ($recursive === TRUE || (is_int($recursive) && $recursive_level <= $recursive)) {
812
- $retval = array_merge($retval, $this->find_product_and_module_files($filename_abspath, $recursive));
813
- }
814
 
815
- elseif (@file_exists(($module_abspath = $filename_abspath.DIRECTORY_SEPARATOR.'module.'.$filename.'.php'))) {
816
- $filename = 'module.'.$filename.'.php';
817
- $filename_abspath = $module_abspath;
818
- }
819
- elseif (@file_exists(($product_abspath = $filename_abspath.DIRECTORY_SEPARATOR.'product.'.$filename.'.php'))) {
820
- $filename = 'product.'.$filename.'.php';
821
- $filename_abspath = $module_abspath;
822
- }
 
 
 
 
 
823
 
824
- }
825
 
826
- if ((strpos($filename, 'module.') === 0 OR strpos($filename, 'product.') === 0) AND !$this->is_blacklisted($filename)) {
827
- $retval[] = $filename_abspath;
 
828
  }
829
  }
830
  }
793
  $recursive_level++;
794
 
795
  $abspath = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $abspath);
796
+ if (!in_array($abspath, $exclusions))
797
+ {
798
  $contents = @scandir($abspath);
799
+ if ($contents)
800
+ {
801
+ foreach ($contents as $filename) {
802
+ if (in_array($filename, $exclusions))
803
+ continue;
804
+ $filename_abspath = $abspath . DIRECTORY_SEPARATOR . $filename;
805
+
806
+ // Is this a subdirectory?
807
+ // We don't use is_dir(), as it's less efficient than just checking for a 'dot' in the filename.
808
+ // The problem is that we're assuming that our directories won't contain a 'dot'.
809
+ if ($recursive && strpos($filename, '.') === FALSE)
810
+ {
 
 
 
 
811
 
812
+ // The recursive parameter can either be set to TRUE or the number of levels to navigate
813
+ // If we reach the max number of recursive levels we're supported to navigate, then we try
814
+ // to guess if there's a module or product file under the directory with the same name as
815
+ // the directory
816
+ if ($recursive === TRUE || (is_int($recursive) && $recursive_level <= $recursive)) {
817
+ $retval = array_merge($retval, $this->find_product_and_module_files($filename_abspath, $recursive));
818
+ } elseif (file_exists(($module_abspath = $filename_abspath . DIRECTORY_SEPARATOR . 'module.' . $filename . '.php'))) {
819
+ $filename = 'module.' . $filename . '.php';
820
+ $filename_abspath = $module_abspath;
821
+ } elseif (@file_exists(($product_abspath = $filename_abspath . DIRECTORY_SEPARATOR . 'product.' . $filename . '.php'))) {
822
+ $filename = 'product.' . $filename . '.php';
823
+ $filename_abspath = $module_abspath;
824
+ }
825
 
826
+ }
827
 
828
+ if ((strpos($filename, 'module.') === 0 or strpos($filename, 'product.') === 0) and !$this->is_blacklisted($filename)) {
829
+ $retval[] = $filename_abspath;
830
+ }
831
  }
832
  }
833
  }
vendor/imagely/pope-framework/lib/class.extensibleobject.php CHANGED
File without changes
vendor/imagely/pope-framework/lib/interface.component_factory.php CHANGED
File without changes