Gallery+ — full-featured gallery with masonry grid, infinite scroll, lightbox, 6 album privacy levels (password, 18+ included), categories, tags, likes, EXIF/GPS, Leaflet maps, embed codes, and 5 widgets AJAX likes, collaborative albums, bcrypt password protection, adult content with karma gate, XMP description extraction, no-crop WebP preset instead of storing originals, 3 view modes (albums, infinite scroll, paged), custom lightbox (swipe/likes/comments/shares), 5 widgets (Random, Photos, Albums, Categories, Map), Leaflet geo-maps, admin cleanup tool
- InstantCMS 2.18.2+
- PHP 7.4+ (developed and tested on PHP 8.2)
- PHP modules:
mbstring— required (auto-titles usemb_strlen/mb_substr)json— built-in (always available in PHP 8.x)simplexml— built-in, used for XMP description extraction on uploadexif— optional; enables EXIF/GPS reading on upload (skipped if absent)curl— optional; used for external APIs (map widget geolocation, update check). If absent,allow_url_fopen=Onis used as a fallback (file_get_contentswith a stream context)
- Image processing uses InstantCMS presets, so the same image modules as the CMS (GD2 or ImageMagick) are required
- Web server: Apache or nginx + PHP-FPM, database MySQL/MariaDB (same as the CMS)
- InstantCMS 2.18.2+
- PHP 7.4+ (разработано и протестировано на PHP 8.2)
- Модули PHP:
mbstring— обязателен (авто-заголовки используютmb_strlen/mb_substr)json— встроенный (в PHP 8.x есть всегда)simplexml— встроенный, используется для извлечения XMP-описаний при загрузкеexif— опционально; включает чтение EXIF/GPS при загрузке (если нет — пропускается)curl— опционально; используется для внешних API (геолокация виджета карты, проверка обновлений). Если нет — используется fallback наallow_url_fopen=On(file_get_contentsс stream context)
- Обработка изображений идёт через пресеты ядра InstantCMS, поэтому нужны те же модули изображений, что и для CMS (GD2 или ImageMagick)
- Веб-сервер: Apache или nginx + PHP-FPM, база данных MySQL/MariaDB (как у CMS)
The visitor's location is resolved by IP on the server (PHP); the browser does not request anything.
How it works (widgets/map/widget.php):
cmsUser::getIp()— visitor IP from the InstantCMS core (detect_ip_keyconfig option, usuallyREMOTE_ADDR).- Cache check:
cache/galleryplus_map/<md5(ip)>.jsonfor 24 hours — to avoid calling an external API on every render. - If there is no cache → external request via
httpGetJson():- ip-api.com —
http://ip-api.com/json/{ip}?fields=status,lat,lon,query(free, no API key); - on failure — ipwho.is —
https://ipwho.is/{ip}(free, no API key, HTTPS).
- ip-api.com —
- If coordinates are obtained, the map center is set to that point; on failure (local/private IP, service unavailable) — the configured center is used.
Required PHP modules: none specific.
- Either
allow_url_fopen=On(thenfile_get_contentswith a stream context works) or the curl extension — the code tries both. jsonis built-in (always available in PHP 8.x). geoip/GeoIP2 are not required and not used.
Accuracy — this is IP geolocation from provider databases, not GPS:
- Usually resolves to a city/locality; coordinates are the city center, error from ~1–2 km (city) to tens of km (small towns, regions).
- Worse on mobile networks (3G/4G) — may show the operator's city/region.
- Private/local IPs (127.x, 10.x, 192.168.x, 172.16–31.x) and corporate VPN/proxies are not resolved → fallback to the configured center.
- Good enough for a "where is the visitor" widget; meter-accurate positioning would require browser geolocation, but it asks for permission, which contradicts the task.
Rate limits: the ip-api.com free tier allows ~45 requests/minute from one server IP — hence the 24-hour per-visitor-IP cache.
Определяем местоположение по IP посетителя на сервере (PHP), браузер ничего не запрашивает.
Как это работает (widgets/map/widget.php):
cmsUser::getIp()— IP посетителя из ядра InstantCMS (detect_ip_keyиз конфига, обычноREMOTE_ADDR).- Проверка кеша:
cache/galleryplus_map/<md5(ip)>.jsonна сутки — чтобы не дёргать внешний API при каждом рендере. - Нет кеша → внешний запрос к
httpGetJson():- ip-api.com —
http://ip-api.com/json/{ip}?fields=status,lat,lon,query(бесплатно, без ключа); - при неудаче ipwho.is —
https://ipwho.is/{ip}(бесплатно, без ключа, https).
- ip-api.com —
- Если получили координаты — центр карты ставится в эту точку; если fail (локальный/приватный IP, сервис недоступен) — используется заданный в настройках центр.
Необходимые модули PHP: специальных нет.
- Нужен либо
allow_url_fopen=On(тогда работаетfile_get_contentsс stream context), либо расширение curl — код пробует оба варианта. json(встроенный, в PHP 8.x всегда есть). geoip/GeoIP2 не требуются и не используются.
Точность — это IP-геолокация по базам провайдера, не GPS:
- Обычно определяет до города/населённого пункта; координаты — центр города, погрешность от ~1–2 км (город) до десятков км (мелкие населённые пункты, регионы).
- Для мобильного интернета (3G/4G) хуже — может показывать город/регион оператора.
- Приватные/локальные IP (127.x, 10.x, 192.168.x, 172.16–31.x) и корпоративные VPN/прокси — не определяются → fallback на заданный центр.
- Для виджета «где сейчас посетитель» этого достаточно; для точного позиционирования (метры) нужна была бы браузерная геолокация, но она требует запроса разрешения у пользователя, что противоречит задаче.
Ограничения по лимитам: ip-api.com бесплатно даёт ~45 запросов/мин с одного IP сервера — поэтому и стоит суточный кеш по IP посетителя.
