HEX
Server: LiteSpeed
System: Linux php-prod-3.spaceapp.ru 5.15.0-151-generic #161-Ubuntu SMP Tue Jul 22 14:25:40 UTC 2025 x86_64
User: sarli3128 (1010)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/retile.ru/public_html/catalog/controller/extension/module/uni_pwa.php
<?php
class ControllerExtensionModuleUniPwa extends Controller {
	public function index() {
		$uniset = $this->config->get('config_unishop2');
		$store_id = (int)$this->config->get('config_store_id');
		$lang_id = (int)$this->config->get('config_language_id');
		
		$data['pwa_notification'] = [];
		
		if(!isset($uniset['pwa']['status']) || !$uniset['pwa']['icon'] || !$this->request->server['HTTPS']) {
			return;
		}
		
		$sw_name = 'uni-sw.'.$store_id.'.js';
		
		$this->setManifest();
		$this->installSW($sw_name);
		$this->setSW($sw_name);
		
		if(!isset($this->request->cookie['pwaOffTime'])) {
			$this->document->addStyle('catalog/view/theme/unishop2/stylesheet/pwa.css');
			
			//$this->document->addScript('catalog/view/theme/unishop2/js/pwacompat.js');
			
			$data['notification'] = [
				'text_chromium' => html_entity_decode($uniset['pwa']['banner']['text_chromium'][$lang_id], ENT_QUOTES, 'UTF-8'),
				'text_other'	=> html_entity_decode($uniset['pwa']['banner']['text_other'][$lang_id], ENT_QUOTES, 'UTF-8'),
				'text_install'	=> $this->language->get('text_pwa_install'),
				'text_close'	=> $this->language->get('text_pwa_not_now')
			];
		}
		
		return $this->load->view('extension/module/uni_pwa_notification', $data);
	}
	
	public function setPwaBannerTopTimeOff() {
		$uniset = $this->config->get('config_unishop2');
		$time = $uniset['pwa']['banner']['time']*3600;
		
		setcookie('pwaOffTime', true, time()+$time, '/');
	}
	
	public function fallbackPage() {
		$uniset = $this->config->get('config_unishop2');
		$lang_id = (int)$this->config->get('config_language_id');
		
		$data = [];
		
		if(isset($uniset['pwa']['status'])) {
			if (is_file(DIR_IMAGE . $this->config->get('config_icon'))) {
				$icon = $this->config->get('config_ssl') . 'image/' . $this->config->get('config_icon');
			} else {
				$icon = '';
			}
			
			$style  = 'a {color:#'.$uniset['a_color'].'}';
			$style .= '.btn-primary {color:#'.$uniset['btn_primary_color'].';background:#'.$uniset['btn_primary_bg'].'}';
			$style .= '.btn-primary:hover, .btn-primary:focus {color:#'.$uniset['btn_primary_color_hover'].';background:#'.$uniset['btn_primary_bg_hover'].'}';
			
			$data['result'] = [
				'title' 		=> $uniset['pwa']['fallbackpage']['title'][$lang_id],
				'icon'			=> $icon,
				'style' 		=> $style,
				'font'			=> $uniset['font'],
				'image'			=> $this->getImg(),
				'description' 	=> html_entity_decode(trim($uniset['pwa']['fallbackpage']['description'][$lang_id]), ENT_QUOTES, 'UTF-8')
			];
		} else {
			$this->response->addHeader($this->request->server['SERVER_PROTOCOL'] . ' 404 Not Found');
		}
		
		$this->response->setOutput($this->load->view('extension/module/uni_pwa_fallback_page', $data));
	}
	
	private function setManifest() {
		$uniset = $this->config->get('config_unishop2');
		$store_id = (int)$this->config->get('config_store_id');
		$lang_id = (int)$this->config->get('config_language_id');
		
		$this->load->model('tool/image');
		
		$manifest = 'catalog/view/theme/unishop2/manifest/manifest.'.$lang_id.'.'.$store_id.'.json';
		
		if (!file_exists($manifest)) {
			$img_sizes = [16, 32, 72, 76, 96, 128, 144, 152, 192, 384, 512];
		
			$icons = '';
			
			$image_old = $uniset['pwa']['icon'];
			$extension = pathinfo($image_old, PATHINFO_EXTENSION);
				
			foreach($img_sizes as $key => $size) {
				$icons .= ' {"src": "'.$this->getImg($size).'", "type": "image/png", "sizes": "'.$size.'x'.$size.'"'. ($key + 1 == count($img_sizes) ? ', "purpose": "any maskable"}' : '},');
			}
		
			$manifest_data = '{
				"dir": "ltr",
				"lang": "'.$this->language->get('code').'",
				"name": "'.$uniset['pwa']['name'][$lang_id].'",
				"short_name": "'.$uniset['pwa']['short_name'][$lang_id].'",
				"scope": "/",
				"display": "standalone",
				"start_url": "/",
				"background_color": "#ffffff",
				"theme_color": "#'.(($uniset['menu_type'] == 1) ? $uniset['main_menu_bg'] : $uniset['main_menu2_bg']).'",
				"orientation": "any",
				"related_applications": [],
				"prefer_related_applications": false,
				"icons": ['.$icons.'],
				"url": "/"
			}';
		
			file_put_contents($manifest, $manifest_data);
		}
		
		$this->document->addLink($manifest, 'manifest');
		$this->document->addLink($this->getImg(152), 'apple-touch-icon');
		
		if(method_exists('document', 'getOgImage') && !$this->document->getOgImage()) {
			$this->document->setOgImage($this->getImg(192));
		}
	}
	
	private function getImg($size = 512){
		//it's all here, because the modules for converting images to webp format can be installed 
		
		$uniset = $this->config->get('config_unishop2');
		
		$image_old = $uniset['pwa']['icon'];
		
		if(!file_exists(DIR_IMAGE.$image_old)) {
			return;
		}
		
		$size = (int)$size;
		
		$extension = pathinfo($image_old, PATHINFO_EXTENSION);
		
		$image_new = 'cache/' . utf8_substr($image_old, 0, utf8_strrpos($image_old, '.')) . '-' . $size . 'x' . $size . '.' . $extension;
				
		if(!is_file(DIR_IMAGE . $image_new) || (filemtime(DIR_IMAGE . $image_old) > filemtime(DIR_IMAGE . $image_new))) {
			$path = '';

			$directories = explode('/', dirname($image_new));

			foreach ($directories as $directory) {
				$path = $path . '/' . $directory;

				if (!is_dir(DIR_IMAGE . $path)) {
					@mkdir(DIR_IMAGE . $path, 0777);
				}
			}
					
			$image = new Image(DIR_IMAGE . $image_old);
			$image->resize($size, $size);
			$image->save(DIR_IMAGE . $image_new);
		}
		
		return $this->config->get('config_ssl') . 'image/'.$image_new;
	}
	
	private function installSW($sw_name) {
		$uniset = $this->config->get('config_unishop2');
		$store_id = (int)$this->config->get('config_store_id');
		$lang_id = (int)$this->config->get('config_language_id');
		
		$date = isset($uniset['save_date']) ? $uniset['save_date'] : strtotime('now');
		
		$install_sw_name = 'catalog/view/theme/unishop2/js/install-sw.'.$store_id.'.js';
		
		if (!file_exists($install_sw_name )) {
			
			$pwaBannerChromium = isset($uniset['pwa']['banner']['text_chromium'][$lang_id]) && $uniset['pwa']['banner']['text_chromium'][$lang_id] != '' ? true : false;
			$pwaBannerOther = isset($uniset['pwa']['banner']['text_other'][$lang_id]) && $uniset['pwa']['banner']['text_other'][$lang_id] != '' ? true : false;
			
			$install_sw_data = '
				const swUrl = "'.$sw_name.'",
					  userAgent = navigator.userAgent.toLowerCase(),
					  touchSupport = (\'ontouchstart\' in document.documentElement),
					  pwaOffTimeCookie = document.cookie.match(\'pwaOffTime\') ? true : false,
					  pwaBannerChromium = "'.$pwaBannerChromium.'",
					  pwaBannerOther = "'.$pwaBannerOther.'",
					  displayStandalone = (window.matchMedia(\'(display-mode:standalone)\').matches || ((\'standalone\' in navigator) && navigator.standalone)) ? true : false;
				
				window.addEventListener(\'load\', () => {
					if (\'serviceWorker\' in navigator) {
						if (!navigator.serviceWorker.controller) {
							navigator.serviceWorker.register(swUrl, {scope: "/"});
						}
					}

					function showNetworkStatusAlert() {
						if(navigator.onLine) {
							uniFlyAlert(\'success\', uniJsVars.pwa.text_online);
						} else {
							uniFlyAlert(\'danger\', uniJsVars.pwa.text_offline);
						}
					}
					
					window.addEventListener(\'online\', showNetworkStatusAlert);
					window.addEventListener(\'offline\', showNetworkStatusAlert);
					
					$(document).ajaxError(() => {
						if(!navigator.onLine) {
							uniFlyAlert(\'danger\', uniJsVars.pwa.text_offline);
						}
					});
					
					if((/iphone|ipad|ipod|firefox|opr/.test(userAgent)) && touchSupport && pwaBannerOther) {
						uniShowPWABanner(\'other\');
					}
					
					uniReloadSW();
					
					if(displayStandalone) {
						if(!$(\'.fly-block .fly-block__back\').length) {
							$(\'.fly-block\').prepend(\'<div class="fly-block__item fly-block__back" onclick="window.history.back();"><i class="fas fa-arrow-left"></i></div>\');
						}
					
						window.onbeforeunload = () => {
							$(\'html\').append(\'<div class="preloader"></div>\');
						};
						
						window.onunload = () => {
							$(\'html .preloader\').remove();
						};
					}
				});
				
				var deferredPrompt;

				window.addEventListener(\'beforeinstallprompt\', (e) => {
					e.preventDefault();

					deferredPrompt = e;
					
					if(pwaBannerChromium) {
						uniShowPWABanner(\'chromium\');
					}
							
					$(document).on(\'click\', \'.pwa-notification__install\', () => {
						deferredPrompt.prompt();
					});
				});
				
				window.addEventListener(\'appinstalled\', () => {
					$(\'.pwa-notification .container\').removeClass(\'active\');
					deferredPrompt = null;
				});
				
				function uniShowPWABanner(newClass){
					if (!pwaOffTimeCookie && !displayStandalone) {
						if(newClass == \'chromium\') $(\'.pwa-notification\').removeClass(\'other\');
							
						$(\'header\').before($(\'.pwa-notification\').removeClass(\'hidden\').addClass(newClass));
						
						setTimeout(() => {			
							$(\'.pwa-notification .container\').addClass(\'active\');
						}, 50);
							
						$(document).on(\'click\', \'.pwa-notification__close\', () => {
							$.get(\'index.php?route=extension/module/uni_pwa/setPwaBannerTopTimeOff\');
							$(\'.pwa-notification .container\').removeClass(\'active\');
						});
					}
				}
				
				function uniSendNotification(title, options) {
					if (\'Notification\' in window) {
						navigator.serviceWorker.ready.then((reg) => {
							if (Notification.permission === \'granted\') {
								reg.showNotification(title, options);
							} else if (Notification.permission !== \'denied\') {
								Notification.requestPermission((permission) => {
									if (permission === "granted") {
										reg.showNotification(title, options);
									}
								});
							}
						});
					}
				}
				
				function uniReloadSW() {
					if (\'serviceWorker\' in navigator) {
						navigator.serviceWorker.ready.then((reg) => {
							if (reg.waiting) {
								reg.waiting.postMessage({ type: \'SKIP_WAITING\' });

								if (displayStandalone) {
									uniSendNotification(\'Update\', {
										body: uniJsVars.pwa.text_reload,
										vibrate: [100, 50, 100],
										tag: \'uniReloadSW\'
									});
								};
							};
						});
					};
				};
				
				function uniDelPageCache(name) {
					caches.keys().then((cacheNames) => {
						cacheNames.forEach(cacheName => {
							if(typeof(name) == \'undefined\' || cacheName == name) {
								caches.delete(cacheName);
							}
						});
					});
				};
				
				$(document).on(\'click\', \'.top-menu__currency-item, .top-menu__language-item\', () => {
					uniDelPageCache();
				});
			';
			
			file_put_contents($install_sw_name, $install_sw_data);
		}
		
		$this->document->addScript($install_sw_name.'?v='.$date);
	}
	
	private function setSW($sw_name) {
		$uniset = $this->config->get('config_unishop2');
		
		if (file_exists($sw_name)) {
			return;
		}
		
		$sw_data = '
			importScripts("catalog/view/theme/unishop2/js/workbox/workbox-sw.js");
			
			const pageCache = "page",
				  jsCache = "js",
				  cssCache = "css",
				  imgCache = "img",
				  fontCache = "fonts",
				  preCache = "fallback",
				  fallbackPage = "index.php?route=extension/module/uni_pwa/fallbackPage",
				  fallbackCss = "catalog/view/theme/unishop2/stylesheet/stylesheet.css",
				  fallbackFontCss = "catalog/view/theme/unishop2/stylesheet/'.$uniset['font'].'.css",
				  fallbackImg = "'.$this->getImg().'";
			
			self.addEventListener(\'activate\', async (event) => {
				event.waitUntil(
					caches.open(preCache).then(cache => {
						cache.addAll([
							fallbackPage,
							fallbackCss,
							fallbackFontCss,
							fallbackImg
						]);
					})
				);
				
				event.waitUntil(clients.claim());
			});

			self.addEventListener(\'message\', async (event) => {
				if (event.data && event.data.type === "SKIP_WAITING") {
					self.skipWaiting();
					
					caches.keys().then(cacheNames => {
						cacheNames.forEach(cacheName => {
							caches.delete(cacheName);
						});
					});
				}
			});
			
			workbox.setConfig({
				modulePathPrefix: "catalog/view/theme/unishop2/js/workbox/"
			});
			
			const documentStrategy = \''.$uniset['pwa']['cache']['document']['strategy'].'\';

			if (documentStrategy == \'NetworkFirst\' && workbox.navigationPreload.isSupported()) {
				//workbox.navigationPreload.enable();
			}

			workbox.routing.registerRoute(
				({event, url}) => event.request.destination === \'document\' && !(/account|wishlist|compare|checkout|cart|admin|login|register|captcha/i.test(url.href)),
				new workbox.strategies.'.$uniset['pwa']['cache']['document']['strategy'].'({
					cacheName: pageCache,
					plugins: [
						new workbox.expiration.ExpirationPlugin({
							maxEntries: '.$uniset['pwa']['cache']['document']['items'].',
							maxAgeSeconds: 60 * 60 * 24 * '.$uniset['pwa']['cache']['document']['lifetime'].',
						}),
					],
				})
			);

			workbox.routing.registerRoute(
				({event, url}) => event.request.destination === \'script\' && !url.pathname.startsWith(\'/admin/\'),
				new workbox.strategies.'.$uniset['pwa']['cache']['script']['strategy'].'({
					cacheName: jsCache,
					plugins: [
						new workbox.expiration.ExpirationPlugin({
							maxEntries: '.$uniset['pwa']['cache']['script']['items'].',
							maxAgeSeconds: 60 * 60 * 24 * '.$uniset['pwa']['cache']['script']['lifetime'].',
						}),
					],
				})
			);

			workbox.routing.registerRoute(
				({event, url}) => event.request.destination === \'style\' && !url.pathname.startsWith(\'/admin/\'),
				new workbox.strategies.'.$uniset['pwa']['cache']['style']['strategy'].'({
					cacheName: cssCache,
					plugins: [
						new workbox.expiration.ExpirationPlugin({
							maxEntries: '.$uniset['pwa']['cache']['style']['items'].',
							maxAgeSeconds: 60 * 60 * 24 * '.$uniset['pwa']['cache']['style']['lifetime'].',
						}),
					],
				})
			);

			workbox.routing.registerRoute(
				({event, url}) => event.request.destination === \'image\' && !(/captcha/i.test(url.href)),
				new workbox.strategies.'.$uniset['pwa']['cache']['image']['strategy'].'({
					cacheName: imgCache,
					plugins: [
						new workbox.expiration.ExpirationPlugin({
							maxEntries: '.$uniset['pwa']['cache']['image']['items'].',
							maxAgeSeconds: 60 * 60 * 24 * '.$uniset['pwa']['cache']['image']['lifetime'].',
							purgeOnQuotaError: true
						}),
					],
				})
			);

			workbox.routing.registerRoute(
				({event}) => event.request.destination === \'font\',
				new workbox.strategies.CacheFirst({
					cacheName: fontCache,
					plugins: [
						new workbox.expiration.ExpirationPlugin({
							maxEntries: 15,
						}),
					],
				})
			);

			workbox.routing.setCatchHandler(
				({event, url}) => {
					if ((event.request.destination) == \'document\') return caches.match(fallbackPage);
				}
			);
		';
		
		file_put_contents($sw_name, $sw_data);
	}
}