api.photostorage.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. <?php
  2. /**
  3. * PhotoStorage allows to attach images for any kind of items on some scope
  4. */
  5. class PhotoStorage {
  6. /**
  7. * Contains system photostorage.ini config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $photoCfg = array();
  12. /**
  13. * Contains system alter config as key=>value
  14. *
  15. * @var array
  16. */
  17. protected $altCfg = array();
  18. /**
  19. * Contains array of available images in database as id=>imagedata
  20. *
  21. * @var array
  22. */
  23. protected $allimages = array();
  24. /**
  25. * Contains loaded images count for each item in some scope as scope=>itemid=>count
  26. *
  27. * @var array
  28. */
  29. protected $imagesCount = array();
  30. /**
  31. * Contains loaded images paths for each item in some scope as scope=>itemid=>imagesList
  32. *
  33. * @var array
  34. */
  35. protected $imagesList = array();
  36. /**
  37. * Contains current photostorage items scope
  38. *
  39. * @var string
  40. */
  41. protected $scope = '';
  42. /**
  43. * Contains current instance item ID in the current scope
  44. *
  45. * @var string
  46. */
  47. protected $itemId = '';
  48. /**
  49. * Contains current administrator login
  50. *
  51. * @var string
  52. */
  53. protected $myLogin = '';
  54. /**
  55. * Flag for preventing multiple database requests
  56. *
  57. * @var bool
  58. */
  59. protected $imagesLoadedFlag = false;
  60. /**
  61. * Use photostorage as image proxy flag
  62. *
  63. * @var bool
  64. */
  65. protected $proxyMode = false;
  66. /**
  67. * Contains images storage path. May be specified in PHOTOSTORAGE_DIRECTORY option.
  68. *
  69. * @var string
  70. */
  71. protected $storagePath = 'content/documents/photostorage/';
  72. /**
  73. * Custom, optional images display prefix URL. Configurable via PHOTOSTORAGE_URL_PREFIX option.
  74. *
  75. * @var string
  76. */
  77. protected $storageUrlPrefix = '';
  78. /**
  79. * Some predefined paths and URLs
  80. */
  81. const UPLOAD_URL_WEBC = '?module=photostorage&uploadcamphoto=true';
  82. const UPLOAD_URL_FILE = '?module=photostorage&uploadfilephoto=true';
  83. const MODULE_URL = '?module=photostorage';
  84. const ROUTE_PROXY = 'getimg';
  85. const EX_NOSCOPE = 'NO_OBJECT_SCOPE_SET';
  86. const EX_WRONG_EXT = 'WRONG_FILE_EXTENSION';
  87. const WATRERMARK_PATH = 'content/documents/watermark.png';
  88. /**
  89. * Initializes photostorage engine for some scope/item id
  90. *
  91. * @param string $scope
  92. * @param string $itemid
  93. *
  94. * @return void
  95. */
  96. public function __construct($scope = '', $itemid = '') {
  97. $this->loadConfig();
  98. $this->loadAlter();
  99. $this->setOptions();
  100. $this->setScope($scope);
  101. $this->setItemid($itemid);
  102. $this->setLogin();
  103. }
  104. /**
  105. * Object scope setter
  106. *
  107. * @param string $scope Object actual scope
  108. *
  109. * @return void
  110. */
  111. protected function setScope($scope) {
  112. $this->scope = ubRouting::filters($scope, 'mres');
  113. }
  114. /**
  115. * Object scope item Id setter
  116. *
  117. * @param string $scope Object actual id in current scope
  118. *
  119. * @return void
  120. */
  121. protected function setItemid($itemid) {
  122. $this->itemId = ubRouting::filters($itemid, 'mres');
  123. }
  124. /**
  125. * Loads system photostorage config into private prop
  126. *
  127. * @return void
  128. */
  129. protected function loadConfig() {
  130. global $ubillingConfig;
  131. $this->photoCfg = $ubillingConfig->getPhoto();
  132. }
  133. /**
  134. * Sets some current instance specific options.
  135. *
  136. * @return void
  137. */
  138. protected function setOptions() {
  139. if (@$this->altCfg['PHOTOSTORAGE_DIRECTORY']) {
  140. $this->storagePath = $this->altCfg['PHOTOSTORAGE_DIRECTORY'];
  141. }
  142. if (@$this->altCfg['PHOTOSTORAGE_URL_PREFIX']) {
  143. $this->storageUrlPrefix = $this->altCfg['PHOTOSTORAGE_URL_PREFIX'];
  144. }
  145. if (@$this->altCfg['PHOTOSTORAGE_PROXY_MODE']) {
  146. $this->proxyMode = true;
  147. }
  148. }
  149. /**
  150. * Loads system alter config into private prop
  151. *
  152. * @return void
  153. */
  154. protected function loadAlter() {
  155. global $ubillingConfig;
  156. $this->altCfg = $ubillingConfig->getAlter();
  157. }
  158. /**
  159. * Administrator login setter
  160. *
  161. * @return void
  162. */
  163. protected function setLogin() {
  164. $this->myLogin = whoami();
  165. }
  166. /**
  167. * Loads images list from database into private prop
  168. *
  169. * @return void
  170. */
  171. protected function loadAllImages() {
  172. if ((!empty($this->scope)) and (!empty($this->itemId))) {
  173. $query = "SELECT * from `photostorage` ORDER by `id` ASC;";
  174. $all = simple_queryall($query);
  175. $this->imagesLoadedFlag = true;
  176. if (!empty($all)) {
  177. foreach ($all as $io => $each) {
  178. $this->allimages[$each['id']] = $each;
  179. $this->imagesList[$each['scope']][$each['item']][] = $each['filename'];
  180. if (isset($this->imagesCount[$each['scope']][$each['item']])) {
  181. $this->imagesCount[$each['scope']][$each['item']]++;
  182. } else {
  183. $this->imagesCount[$each['scope']][$each['item']] = 1;
  184. }
  185. }
  186. }
  187. }
  188. }
  189. /**
  190. * Registers uploaded image in database
  191. *
  192. * @param string $filename
  193. */
  194. protected function registerImage($filename) {
  195. if ((!empty($this->scope)) and (!empty($this->itemId))) {
  196. $filename = mysql_real_escape_string($filename);
  197. $date = curdatetime();
  198. $query = "INSERT INTO `photostorage` (`id`, `scope`, `item`, `date`, `admin`, `filename`) "
  199. . "VALUES (NULL, '" . $this->scope . "', '" . $this->itemId . "', '" . $date . "', '" . $this->myLogin . "', '" . $filename . "'); ";
  200. nr_query($query);
  201. log_register('PHOTOSTORAGE CREATE SCOPE `' . $this->scope . '` ITEM [' . $this->itemId . ']');
  202. }
  203. }
  204. /**
  205. * Deletes uploaded image from database
  206. *
  207. * @param int $imageid
  208. */
  209. protected function unregisterImage($imageid) {
  210. if ((!empty($this->scope)) and (!empty($this->itemId))) {
  211. $imageid = vf($imageid, 3);
  212. $date = curdatetime();
  213. $query = "DELETE from `photostorage` WHERE `id`='" . $imageid . "';";
  214. nr_query($query);
  215. log_register('PHOTOSTORAGE DELETE SCOPE `' . $this->scope . '` ITEM [' . $this->itemId . ']');
  216. }
  217. }
  218. /**
  219. * Returns basic image controls
  220. *
  221. * @param int $imageId existing image ID
  222. * @return string
  223. */
  224. protected function imageControls($imageId) {
  225. $result = wf_tag('br');
  226. $downloadUrl = self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&download=' . $imageId;
  227. $result .= wf_Link($downloadUrl, wf_img('skins/icon_download.png') . ' ' . __('Download'), false, 'ubButton') . ' ';
  228. if (cfr('PHOTOSTORAGEDELETE')) {
  229. $deleteUrl = self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&delete=' . $imageId;
  230. $result .= wf_AjaxLink($deleteUrl, web_delete_icon() . ' ' . __('Delete'), 'ajRefCont_' . $imageId, false, 'ubButton') . ' ';
  231. }
  232. return ($result);
  233. }
  234. /**
  235. * Returns image upload controls
  236. *
  237. * @return string
  238. */
  239. public function uploadControlsPanel() {
  240. $result = '';
  241. if ((!empty($this->scope)) and (!empty($this->itemId))) {
  242. $result .= wf_Link(self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&mode=cam', wf_img('skins/photostorage.png') . ' ' . __('Webcamera snapshot'), false, 'ubButton');
  243. $result .= wf_Link(self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&mode=loader', wf_img('skins/photostorage_upload.png') . ' ' . __('Upload file from HDD'), false, 'ubButton');
  244. }
  245. return ($result);
  246. }
  247. /**
  248. * Returns custom module backlinks for some scopes
  249. *
  250. * @return string
  251. */
  252. protected function backUrlHelper() {
  253. $result = '';
  254. if ($this->scope == 'USERPROFILE') {
  255. $result = web_UserControls($this->itemId);
  256. }
  257. if ($this->scope == 'CUSTMAPSITEMS') {
  258. $result = wf_BackLink('?module=custmaps&edititem=' . $this->itemId);
  259. }
  260. if ($this->scope == 'WAREHOUSEITEMTYPE') {
  261. $result = wf_BackLink('?module=warehouse&itemtypes=true');
  262. }
  263. if ($this->scope == 'TASKMAN') {
  264. $result = wf_BackLink('?module=taskman&edittask=' . $this->itemId);
  265. }
  266. if ($this->scope == 'UKVUSERPROFILE') {
  267. $result = wf_BackLink('?module=ukv&users=true&showuser=' . $this->itemId);
  268. }
  269. if ($this->scope == 'CFITEMS') {
  270. $cleanUserLogin = explode(CustomFields::PHOTOSTORAGE_ITEMID_DELIMITER, $this->itemId);
  271. $cleanUserLogin = $cleanUserLogin[0];
  272. $result = wf_BackLink(CustomFields::URL_EDIT_BACK . $cleanUserLogin);
  273. }
  274. if ($this->scope == 'CRMACTIVITY') {
  275. $result = wf_BackLink(PseudoCRM::URL_ME . '&' . PseudoCRM::ROUTE_ACTIVITY_PROFILE . '=' . $this->itemId);
  276. }
  277. return ($result);
  278. }
  279. /**
  280. * Returns count of loaded images for some itemid in some scope
  281. *
  282. * @param string $itemId
  283. *
  284. * @return int
  285. */
  286. public function getImagesCount($itemId) {
  287. $result = 0;
  288. $this->itemId = $itemId;
  289. if (!$this->imagesLoadedFlag) {
  290. $this->loadAllImages();
  291. }
  292. if (isset($this->imagesCount[$this->scope][$itemId])) {
  293. $result = $this->imagesCount[$this->scope][$itemId];
  294. }
  295. return ($result);
  296. }
  297. /**
  298. * Returns array of links of images for some itemId in current scope if it exists
  299. *
  300. * @param string $itemId
  301. *
  302. * @return array
  303. */
  304. public function getImagesList($itemId) {
  305. $result = array();
  306. $this->itemId = $itemId;
  307. if (!$this->imagesLoadedFlag) {
  308. $this->loadAllImages();
  309. }
  310. if (isset($this->imagesList[$this->scope])) {
  311. if (isset($this->imagesList[$this->scope][$itemId])) {
  312. $imageFiles = $this->imagesList[$this->scope][$itemId];
  313. if (!empty($imageFiles)) {
  314. foreach ($imageFiles as $io => $eachFilename) {
  315. $result[] = $this->getImageUrl($eachFilename);
  316. }
  317. }
  318. }
  319. }
  320. return ($result);
  321. }
  322. /**
  323. * Retuns all available scopes and images count in it as scope=>count
  324. *
  325. * @return array
  326. */
  327. public function getAvailScopes() {
  328. $result = array();
  329. if (!$this->imagesLoadedFlag) {
  330. $this->loadAllImages();
  331. }
  332. if (!empty($this->allimages)) {
  333. foreach ($this->allimages as $io => $each) {
  334. if (isset($result[$each['scope']])) {
  335. $result[$each['scope']]++;
  336. } else {
  337. $result[$each['scope']] = 1;
  338. }
  339. }
  340. }
  341. return ($result);
  342. }
  343. /**
  344. * Returns image HTTP accessable URL
  345. *
  346. * @param string $filename
  347. *
  348. * @return string
  349. */
  350. protected function getImageUrl($filename) {
  351. $result = '';
  352. //Raw HTTP images access
  353. if (!$this->proxyMode) {
  354. if (empty($this->storageUrlPrefix)) {
  355. //seems its local storage
  356. $result = $this->storagePath . $filename;
  357. } else {
  358. //separate images CDN
  359. $result = $this->storageUrlPrefix . $filename;
  360. }
  361. } else {
  362. //Access to images in storage via proxy-engine
  363. $result = self::MODULE_URL . '&' . self::ROUTE_PROXY . '=' . $filename;
  364. }
  365. return ($result);
  366. }
  367. /**
  368. * Returns list of all available images for all scopes
  369. *
  370. * @param int $perPage
  371. * @param bool $checkRights
  372. *
  373. * @return string
  374. */
  375. public function renderScopesGallery($perPage = 12, $checkRights = true) {
  376. $result = '';
  377. $paginator = '';
  378. $scopeImages = array();
  379. $messages = new UbillingMessageHelper();
  380. if (!$this->imagesLoadedFlag) {
  381. $this->loadAllImages();
  382. }
  383. if (!empty($this->allimages)) {
  384. $imgTmp = array_reverse($this->allimages);
  385. if ($checkRights) {
  386. $myImages = array();
  387. if (!cfr('ROOT')) {
  388. if (!empty($imgTmp)) {
  389. foreach ($imgTmp as $io => $each) {
  390. if ($each['admin'] == $this->myLogin) {
  391. $myImages[$io] = $each;
  392. }
  393. }
  394. $imgTmp = $myImages;
  395. }
  396. }
  397. }
  398. $renderImages = array();
  399. $totalCount = sizeof($imgTmp);
  400. $currentPage = (ubRouting::get('page')) ? ubRouting::get('page') : 1;
  401. //pagination
  402. if ($totalCount > $perPage) {
  403. $paginator = wf_pagination($totalCount, $perPage, $currentPage, self::MODULE_URL, 'ubButton', 14);
  404. $lowLimit = ($perPage * ($currentPage - 1));
  405. $upperLimit = $lowLimit + $perPage;
  406. $i = 0;
  407. foreach ($imgTmp as $io => $each) {
  408. if ($i >= $lowLimit and $i < $upperLimit) {
  409. $renderImages[$io] = $each;
  410. }
  411. $i++;
  412. }
  413. } else {
  414. $renderImages = $imgTmp;
  415. }
  416. $galleryRel = 'photostoragegallery';
  417. $previewStyle = 'style="float:left; margin:1px;"';
  418. $result .= wf_tag('link', false, '', 'rel="stylesheet" href="modules/jsc/image-gallery-lightjs/src/jquery.light.css"');
  419. $result .= wf_tag('script', false, '', 'src="modules/jsc/image-gallery-lightjs/src/jquery.light.js"') . wf_tag('script', true);
  420. if (!empty($renderImages)) {
  421. foreach ($renderImages as $io => $eachimage) {
  422. $imgPreview = wf_img_sized($this->getImageUrl($eachimage['filename']), __('Preview'), $this->photoCfg['IMGLIST_PREV_W'], $this->photoCfg['IMGLIST_PREV_H']);
  423. $imgFull = wf_img_sized($this->getImageUrl($eachimage['filename']), '', '100%');
  424. $imgCaption = __('Date') . ': ' . $eachimage['date'] . ' ' . __('Admin') . ': ' . $eachimage['admin'];
  425. $mngUrl = self::MODULE_URL . '&scope=' . $eachimage['scope'] . '&mode=list&itemid=' . $eachimage['item'];
  426. $mngLink = ' ' . wf_Link($mngUrl, __('Show'), false, '', 'target=_blank');
  427. $mngLink = str_replace('"', '', $mngLink);
  428. $imgCaption .= $mngLink;
  429. $galleryOptions = 'data-caption="' . $imgCaption . '" data-gallery="1" rel="' . $galleryRel . '" ' . $previewStyle . '"';
  430. $imgGallery = wf_Link($this->getImageUrl($eachimage['filename']), $imgPreview, false, '', $galleryOptions);
  431. $result .= $imgGallery;
  432. }
  433. } else {
  434. $result .= $messages->getStyledMessage(__('Nothing to show'), 'info');
  435. }
  436. //init gallery
  437. $jsGallery = wf_tag('script');
  438. $jsGallery .= " $('a[rel=" . $galleryRel . "]').light({
  439. unbind:true,
  440. prevText:'" . __('Previous') . "',
  441. nextText:'" . __('Next') . "',
  442. loadText:'" . __('Loading') . "...',
  443. keyboard:true
  444. });
  445. ";
  446. $jsGallery .= wf_tag('script', true);
  447. $result .= $jsGallery;
  448. $result .= wf_CleanDiv();
  449. $result .= $paginator;
  450. } else {
  451. $result .= $messages->getStyledMessage(__('Nothing to show'), 'warning');
  452. }
  453. return ($result);
  454. }
  455. /**
  456. * Returns current scope/item images list
  457. *
  458. * @return string
  459. */
  460. public function renderImagesList() {
  461. if (!$this->imagesLoadedFlag) {
  462. $this->loadAllImages();
  463. }
  464. $result = wf_AjaxLoader();
  465. if (!empty($this->allimages)) {
  466. foreach ($this->allimages as $io => $eachimage) {
  467. if (($eachimage['scope'] == $this->scope) and ($eachimage['item'] == $this->itemId)) {
  468. $imgPreview = wf_img_sized($this->getImageUrl($eachimage['filename']), __('Show'), $this->photoCfg['IMGLIST_PREV_W'], $this->photoCfg['IMGLIST_PREV_H']);
  469. $imgFull = wf_img_sized($this->getImageUrl($eachimage['filename']), '', '100%');
  470. $imgFull .= wf_tag('br');
  471. $imgFull .= __('Date') . ': ' . $eachimage['date'] . ' / ';
  472. $imgFull .= __('Admin') . ': ' . $eachimage['admin'] . ' ';
  473. $dimensions = 'width:' . ($this->photoCfg['IMGLIST_PREV_W'] + 10) . 'px;';
  474. $dimensions .= 'height:' . ($this->photoCfg['IMGLIST_PREV_H'] + 10) . 'px;';
  475. $result .= wf_tag('div', false, '', 'style="float:left; ' . $dimensions . ' padding:15px;" id="ajRefCont_' . $eachimage['id'] . '"');
  476. $result .= wf_modalAuto($imgPreview, __('Image') . ' ' . $eachimage['id'], $imgFull, '');
  477. $result .= $this->imageControls($eachimage['id']);
  478. $result .= wf_tag('div', true);
  479. }
  480. }
  481. }
  482. $result .= wf_tag('div', false, '', 'style="clear:both;"') . wf_tag('div', true);
  483. $result .= wf_delimiter();
  484. $result .= $this->backUrlHelper();
  485. return ($result);
  486. }
  487. /**
  488. * Returns list of available images for current scope/item
  489. *
  490. * @return string
  491. */
  492. public function renderImagesRaw() {
  493. $result = '';
  494. $galleryFlag = ($this->altCfg['PHOTOSTORAGE_GALLERY']) ? true : false;
  495. if (!$this->imagesLoadedFlag) {
  496. $this->loadAllImages();
  497. }
  498. if (!empty($this->allimages)) {
  499. $galleryRel = 'photostoragegallery';
  500. $previewStyle = 'style="float:left; margin:1px;"';
  501. $result .= wf_tag('link', false, '', 'rel="stylesheet" href="modules/jsc/image-gallery-lightjs/src/jquery.light.css"');
  502. $result .= wf_tag('script', false, '', 'src="modules/jsc/image-gallery-lightjs/src/jquery.light.js"') . wf_tag('script', true);
  503. foreach ($this->allimages as $io => $eachimage) {
  504. if (($eachimage['scope'] == $this->scope) and ($eachimage['item'] == $this->itemId)) {
  505. $imgPreview = wf_img_sized($this->getImageUrl($eachimage['filename']), __('Show'), $this->photoCfg['IMGLIST_PREV_W'], $this->photoCfg['IMGLIST_PREV_H']);
  506. $imgFull = wf_img_sized($this->getImageUrl($eachimage['filename']), '', '100%');
  507. $imgCaption = __('Date') . ': ' . $eachimage['date'] . ' ' . __('Admin') . ': ' . $eachimage['admin'];
  508. if ($galleryFlag) {
  509. $galleryOptions = 'data-caption="' . $imgCaption . '" data-gallery="1" rel="' . $galleryRel . '" ' . $previewStyle . '"';
  510. $imgGallery = wf_Link($this->getImageUrl($eachimage['filename']), $imgPreview, false, '', $galleryOptions);
  511. $result .= $imgGallery;
  512. } else {
  513. $result .= wf_modalAuto($imgPreview, __('Image') . ' ' . $eachimage['id'], $imgFull . $imgCaption, '');
  514. }
  515. }
  516. }
  517. //init gallery
  518. $jsGallery = wf_tag('script');
  519. $jsGallery .= " $('a[rel=" . $galleryRel . "]').light({
  520. unbind:true,
  521. prevText:'" . __('Previous') . "',
  522. nextText:'" . __('Next') . "',
  523. loadText:'" . __('Loading') . "...',
  524. keyboard:true
  525. });
  526. ";
  527. $jsGallery .= wf_tag('script', true);
  528. $result .= $jsGallery;
  529. }
  530. $result .= wf_CleanDiv();
  531. return ($result);
  532. }
  533. /**
  534. * Downloads image file by its id
  535. *
  536. * @param int $id database image ID
  537. */
  538. public function catchDownloadImage($id) {
  539. $id = vf($id, 3);
  540. if (!$this->imagesLoadedFlag) {
  541. $this->loadAllImages();
  542. }
  543. if (!empty($id)) {
  544. @$filename = $this->allimages[$id]['filename'];
  545. if (file_exists($this->storagePath . $filename)) {
  546. zb_DownloadFile($this->storagePath . $filename, 'jpg');
  547. } else {
  548. show_error(__('File not exist'));
  549. }
  550. } else {
  551. show_error(__('Image not exists'));
  552. }
  553. }
  554. /**
  555. * Returns some image content as is if proxy mode enabled \
  556. * and image file exists in storage path
  557. *
  558. * @param string $filename
  559. */
  560. public function proxyImage($filename) {
  561. if ($this->proxyMode) {
  562. if (file_exists($this->storagePath . $filename)) {
  563. $imageContent = file_get_contents($this->storagePath . $filename);
  564. die($imageContent);
  565. } else {
  566. $noImage = file_get_contents('skins/noimage.jpg');
  567. die($noImage);
  568. }
  569. } else {
  570. $noImage = file_get_contents('skins/noimage.jpg');
  571. die($noImage);
  572. }
  573. }
  574. /**
  575. * deletes image from database and FS by its ID
  576. *
  577. * @param int $id database image ID
  578. */
  579. public function catchDeleteImage($id) {
  580. $id = vf($id, 3);
  581. if (!$this->imagesLoadedFlag) {
  582. $this->loadAllImages();
  583. }
  584. if (!empty($id)) {
  585. @$filename = $this->allimages[$id]['filename'];
  586. if (file_exists($this->storagePath . $filename)) {
  587. if (cfr('PHOTOSTORAGEDELETE')) {
  588. unlink($this->storagePath . $filename);
  589. $this->unregisterImage($id);
  590. $deleteResult = wf_tag('span', false, 'alert_warning') . __('Deleted') . wf_tag('span', true);
  591. } else {
  592. $deleteResult = wf_tag('span', false, 'alert_error') . __('Access denied') . wf_tag('span', true);
  593. }
  594. } else {
  595. $deleteResult = wf_tag('span', false, 'alert_error') . __('File not exist') . wf_tag('span', true);
  596. }
  597. } else {
  598. $deleteResult = wf_tag('span', false, 'alert_error') . __('Image not exists') . wf_tag('span', true);
  599. }
  600. die($deleteResult);
  601. }
  602. /**
  603. * Catches webcam snapshot upload in background
  604. *
  605. * @return void
  606. */
  607. public function catchWebcamUpload() {
  608. if (wf_CheckGet(array('uploadcamphoto'))) {
  609. if (!empty($this->scope)) {
  610. $newWebcamFilename = date("Y_m_d_His") . '_' . zb_rand_string(8) . '_webcam.jpg';
  611. $newWebcamSavePath = $this->storagePath . $newWebcamFilename;
  612. //get image data
  613. $dataRaw = ubRouting::post('image');
  614. //remove the prefix
  615. $uri = substr($dataRaw, strpos($dataRaw, ","));
  616. //decode the image data and save it to file
  617. file_put_contents($newWebcamSavePath, base64_decode($uri));
  618. if (file_exists($newWebcamSavePath)) {
  619. $uploadResult = wf_tag('span', false, 'alert_success') . __('Photo upload complete') . wf_tag('span', true);
  620. $this->registerImage($newWebcamFilename);
  621. } else {
  622. $uploadResult = wf_tag('span', false, 'alert_error') . __('Photo upload failed') . wf_tag('span', true);
  623. }
  624. } else {
  625. $uploadResult = wf_tag('span', false, 'alert_error') . __('Strange exeption') . ': ' . self::EX_NOSCOPE . wf_tag('span', true);
  626. }
  627. die($uploadResult);
  628. }
  629. }
  630. /**
  631. * Performs some image postprocessing on images uploads
  632. *
  633. * @param string $filePath
  634. *
  635. * @return void
  636. */
  637. public function imagePostProcessing($filePath) {
  638. $result = '';
  639. $pixelCraft = new PixelCraft();
  640. $pixelCraft->loadImage($filePath);
  641. $imageWidth = $pixelCraft->getImageWidth();
  642. $imageHeight = $pixelCraft->getImageHeight();
  643. $originalType = $pixelCraft->getImageType();
  644. $result .= wf_tag('span', false, 'alert_info') . __('Original image dimensions') . ' :' . $imageWidth . 'x' . $imageHeight . wf_tag('span', true);
  645. $fileSizeOrig = filesize($filePath);
  646. $result .= wf_tag('span', false, 'alert_info') . __('Uploaded file size') . ': ' . zb_convertSize($fileSizeOrig) . wf_tag('span', true);
  647. $imgInfo = '';
  648. $imgInfo .= whoami() . ' Date: ' . date("Y-m-d H:i:s") . ' ';
  649. $imgInfo .= 'Orig: ' . $imageWidth . 'x' . $imageHeight . ' ' . $originalType . ', ' . zb_convertSize($fileSizeOrig) . ' ';
  650. //recompressing image
  651. if ($this->altCfg['PHOTOSTORAGE_RECOMPRESS']) {
  652. $quality = -1;
  653. if ($originalType == 'jpeg') {
  654. $quality = 70;
  655. $pixelCraft->setQuality($quality);
  656. }
  657. if ($originalType == 'png') {
  658. $quality = 9;
  659. $pixelCraft->setQuality($quality);
  660. }
  661. $result .= wf_tag('span', false, 'alert_info') . __('Image compression') . ': ' . $quality . wf_tag('span', true);
  662. $imgInfo .= 'Recompress: ' . $quality . ' ';
  663. }
  664. //appending watermark
  665. if ($this->altCfg['PHOTOSTORAGE_WATERMARK']) {
  666. $pixelCraft->loadWatermark(self::WATRERMARK_PATH);
  667. $pixelCraft->drawWatermark(false, $imageWidth - 120, 20);
  668. $result .= wf_tag('span', false, 'alert_info') . __('Watermark applied') . wf_tag('span', true);
  669. }
  670. //automatic downscale of huge images
  671. if ($this->altCfg['PHOTOSTORAGE_AUTORESIZE']) {
  672. $scale = 1;
  673. if ($imageWidth >= 4000 or $imageHeight >= 4000) {
  674. $scale = 0.5;
  675. $pixelCraft->scale($scale);
  676. $imageWidth = $pixelCraft->getImageWidth();
  677. $imageHeight = $pixelCraft->getImageHeight();
  678. } else {
  679. if ($imageWidth >= 2000 or $imageHeight >= 2000) {
  680. $scale = 0.8;
  681. $pixelCraft->scale($scale);
  682. $imageWidth = $pixelCraft->getImageWidth();
  683. $imageHeight = $pixelCraft->getImageHeight();
  684. }
  685. }
  686. if ($scale != 1) {
  687. $result .= wf_tag('span', false, 'alert_info') . __('New image dimensions') . ' :' . $imageWidth . 'x' . $imageHeight . wf_tag('span', true);
  688. $imgInfo .= 'Rescale x' . $scale . ': ' . $imageWidth . 'x' . $imageHeight . ' ';
  689. }
  690. $result .= wf_tag('span', false, 'alert_info') . __('Image scale') . ': ' . $scale . wf_tag('span', true);
  691. }
  692. if ($this->altCfg['PHOTOSTORAGE_DRAWIMGINFO']) {
  693. $infoX = 5;
  694. $infoY = $imageHeight - 10;
  695. $pixelCraft->drawString($infoX, $infoY, $imgInfo, 'yellow', 1, false);
  696. }
  697. //saving post-processed image
  698. $pixelCraft->saveImage($filePath, $originalType);
  699. //updating filesize
  700. clearstatcache(true, $filePath);
  701. $fileSizeProcessed = filesize($filePath);
  702. $result .= wf_tag('span', false, 'alert_info') . __('Saved file size') . ': ' . zb_convertSize($fileSizeProcessed) . wf_tag('span', true);
  703. return ($result);
  704. }
  705. /**
  706. * Catches file upload in background
  707. *
  708. * @param string $customBackLink
  709. *
  710. * @return void
  711. */
  712. public function catchFileUpload($customBackLink = '') {
  713. if (wf_CheckGet(array('uploadfilephoto'))) {
  714. if (!empty($this->scope)) {
  715. $allowedExtensions = array("jpg", "gif", "png", "jpeg");
  716. $fileAccepted = true;
  717. foreach ($_FILES as $file) {
  718. if ($file['tmp_name'] > '') {
  719. //TODO: in PHP 7.1 following string generates notice
  720. if (@!in_array(end(explode(".", strtolower($file['name']))), $allowedExtensions)) {
  721. $fileAccepted = false;
  722. }
  723. }
  724. }
  725. if ($fileAccepted) {
  726. //upload successful?
  727. if (file_exists(@$_FILES['photostorageFileUpload']['tmp_name'])) {
  728. //checking image validity
  729. $pixelCraft = new PixelCraft();
  730. if ($pixelCraft->isImageValid($_FILES['photostorageFileUpload']['tmp_name'])) {
  731. $newFilename = date("Y_m_d_His") . '_' . zb_rand_string(8) . '_upload.jpg';
  732. $newSavePath = $this->storagePath . $newFilename;
  733. @move_uploaded_file($_FILES['photostorageFileUpload']['tmp_name'], $newSavePath);
  734. if (file_exists($newSavePath)) {
  735. $uploadResult = wf_tag('span', false, 'alert_success') . __('Photo upload complete') . wf_tag('span', true);
  736. //image postprocessing
  737. if (@$this->altCfg['PHOTOSTORAGE_POSTPROCESSING']) {
  738. $uploadResult .= $this->imagePostProcessing($newSavePath);
  739. }
  740. $this->registerImage($newFilename);
  741. // forwarding $customBackLink back to renderUploadForm() routine
  742. if (empty($customBackLink)) {
  743. $customBackLink = '';
  744. } else {
  745. $customBackLink = '&custombacklink=' . $customBackLink;
  746. }
  747. ubRouting::nav(self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&mode=loader&preview=' . $newFilename . $customBackLink);
  748. } else {
  749. $uploadResult = wf_tag('span', false, 'alert_error') . __('Photo upload failed') . wf_tag('span', true);
  750. }
  751. } else {
  752. $uploadResult = wf_tag('span', false, 'alert_error') . __('Photo upload failed') . ': ' . __('File') . ' ' . __('is corrupted') . wf_tag('span', true);
  753. }
  754. } else {
  755. $uploadResult = wf_tag('span', false, 'alert_error') . __('Photo upload failed') . ': ' . __('File not found') . wf_tag('span', true);
  756. }
  757. } else {
  758. $uploadResult = wf_tag('span', false, 'alert_error') . __('Photo upload failed') . ': ' . self::EX_WRONG_EXT . wf_tag('span', true);
  759. }
  760. } else {
  761. $uploadResult = wf_tag('span', false, 'alert_error') . __('Strange exeption') . ': ' . self::EX_NOSCOPE . wf_tag('span', true);
  762. }
  763. show_window('', $uploadResult);
  764. show_window('', wf_BackLink(self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&mode=loader'));
  765. }
  766. }
  767. /**
  768. * Returns file upload form
  769. *
  770. * @param bool $embedded
  771. * @param string $customBackLink
  772. *
  773. * @return string
  774. */
  775. public function renderUploadForm($embedded = false, $customBackLink = '') {
  776. // forwarding $customBackLink to catchFileUpload() routine
  777. if (!empty($customBackLink)) {
  778. $customBackLink = '&custombacklink=' . $customBackLink;
  779. }
  780. $postUrl = self::UPLOAD_URL_FILE . '&scope=' . $this->scope . '&itemid=' . $this->itemId . $customBackLink;
  781. $inputs = wf_tag('form', false, 'photostorageuploadform', 'action="' . $postUrl . '" enctype="multipart/form-data" method="POST"');
  782. $inputs .= wf_tag('input', false, '', 'type="file" name="photostorageFileUpload" accept="image/*" required');
  783. $inputs .= wf_Submit(__('Upload'));
  784. $inputs .= wf_tag('form', true);
  785. $result = $inputs;
  786. $result .= wf_delimiter(2);
  787. if (wf_CheckGet(array('preview'))) {
  788. $result .= wf_img_sized($this->getImageUrl(ubRouting::get('preview')), __('Preview'), $this->photoCfg['IMGLIST_PREV_W'], $this->photoCfg['IMGLIST_PREV_H']);
  789. $result .= wf_delimiter();
  790. $result .= wf_tag('span', false, 'alert_success') . __('Photo upload complete') . wf_tag('span', true);
  791. $result .= wf_delimiter();
  792. }
  793. if (!$embedded) {
  794. // checking for forwarded $customBackLink from catchFileUpload() routine
  795. if (ubRouting::checkGet('custombacklink')) {
  796. $result .= wf_BackLink(base64_decode(ubRouting::get('custombacklink')));
  797. } else {
  798. $result .= wf_BackLink(self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&mode=list');
  799. }
  800. }
  801. return ($result);
  802. }
  803. /**
  804. * Returns webcamera snapshot form
  805. *
  806. * @param bool $avatarMode use crop by WEBCAM_AVA_CROP property
  807. *
  808. * @return string
  809. */
  810. public function renderWebcamForm($avatarMode = false) {
  811. $result = '';
  812. $init = wf_tag('link', false, '', 'href="modules/jsc/webcamlib/style.css" rel="stylesheet"') . wf_tag('link', true);
  813. if ($avatarMode) {
  814. $prev_w = $this->photoCfg['WEBCAM_PREV_W'];
  815. $prev_h = $this->photoCfg['WEBCAM_PREV_H'];
  816. $dest_w = $this->photoCfg['WEBCAM_RESULT_W'];
  817. $dest_h = $this->photoCfg['WEBCAM_RESULT_H'];
  818. } else {
  819. $prev_w = $this->photoCfg['WEBCAM_PREV_W'];
  820. $prev_h = $this->photoCfg['WEBCAM_PREV_H'];
  821. $dest_w = $this->photoCfg['WEBCAM_RESULT_W'];
  822. $dest_h = $this->photoCfg['WEBCAM_RESULT_H'];
  823. }
  824. $uploadUrl = self::UPLOAD_URL_WEBC . '&scope=' . $this->scope . '&itemid=' . $this->itemId;
  825. $labelCapture = wf_img('skins/photostorage.png') . ' ' . __('Take snapshot');
  826. $labelCaptureF = str_replace('"', '', $labelCapture);
  827. $labelReCapture = wf_img('skins/photostorage.png') . ' ' . __('Retake photo');
  828. $labelReCaptureF = str_replace('"', '', $labelReCapture);
  829. $labelSave = wf_img('skins/save.png') . ' ' . __('Save');
  830. $labelSaveF = str_replace('"', '', $labelSave);
  831. $container = wf_tag('div', false, 'content');
  832. $container .= wf_tag('div', false, 'webcamholder');
  833. $container .= wf_tag('video', false, '', 'autoplay id="webcamvideo"') . wf_tag('video', true);
  834. $container .= wf_tag('canvas', false, '', 'id="webcamcanvas"') . wf_tag('canvas', true);
  835. $container .= wf_tag('div', true);
  836. $container .= wf_tag('div', true);
  837. $container .= wf_tag('div', false, 'buttons');
  838. $container .= wf_tag('button', false, 'ubButton', 'id="buttonCapture" disabled') . $labelCapture . wf_tag('button', true) . ' ';
  839. $container .= wf_tag('button', false, 'ubButton', 'id="buttonSave" disabled') . $labelSave . wf_tag('button', true);
  840. $container .= wf_tag('div', true);
  841. $container .= wf_tag('div', false, '', 'id="savedImages"');
  842. $container .= wf_tag('div', true);
  843. $uploadJs = wf_tag('script', false, '', 'language="JavaScript"');
  844. $jScript = file_get_contents('modules/jsc/webcamlib/script.js');
  845. eval($jScript);
  846. $uploadJs .= wf_tag('script', true);
  847. $result .= $init;
  848. $result .= $container;
  849. $result .= $uploadJs;
  850. $result .= wf_delimiter(0);
  851. $result .= wf_BackLink(self::MODULE_URL . '&scope=' . $this->scope . '&itemid=' . $this->itemId . '&mode=list');
  852. return ($result);
  853. }
  854. }