diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0755fab --- /dev/null +++ b/.editorconfig @@ -0,0 +1,26 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 86 + +# Matches multiple files with brace expansion notation +# Set default charset +[*.{php,tpl,js,css,xml,py,json,md}] +charset = utf-8 + +# 4 space indentation +[*.{py,md}] +indent_style = space +indent_size = 4 + +# Tab indentation for everything else +[*.{php,tpl,js,css,xml,json}] +indent_style = tab +indent_size = 4 diff --git a/.env.example b/.env.example index d2a256d..0221cf4 100644 --- a/.env.example +++ b/.env.example @@ -77,31 +77,32 @@ USERIMAGE_EXTENSION=".jpg" # Extension with .-prefix USERIMAGE_SIZE_LARGE= USERIMAGE_SIZE_SMALL= USERIMAGE_DEFAULT="none${USERIMAGE_EXTENSION}" # Must be within USERIMAGES_DIR -ADDLE_MAX_GAMES= -ADDLE_BASE_POINTS= -ADDLE_MAX_POINTS_TRANSFERABLE= -APOD_GALLERY_ID= # Match to gallery_albums-Table `id` +ADDLE_MAX_GAMES=1 +ADDLE_BASE_POINTS=1600 +ADDLE_MAX_POINTS_TRANSFERABLE=32 BUGTRACKER_FILTER_DEFAULT="?show[]=open&show[]=notdenied&show[]=assigned&show[]=unassigned" -CHESS_DWZ_BASE_POINTS= -CHESS_DWZ_MAX_POINTS_TRANSFERABLE= -FORUM_DEFAULT_MAXDEPTH= -FORUM_THREAD_CLEARCACHE_AFTER= # In Tagen -GALLERY_MAX_PIC_SIZE="['width'=>800, 'height'=>800]" -GALLERY_MAX_THUMBNAIL_SIZE="['width'=>150, 'height'=>150]" -GALLERY_THUMBPAGE="['width'=>4, 'height'=>3, 'padding'=>10]" -GO_OFFSET_PIC= -GO_LINKRADIUS= -GO_FIELDSIZE= -GO_LINEWIDTH= -GO_STARDOTWIDTH= -GO_STONEBIGWIDTH= -GO_LASTSTONEWIDTH= +CHESS_DWZ_BASE_POINTS=1600 +CHESS_DWZ_MAX_POINTS_TRANSFERABLE=32 +FORUM_DEFAULT_MAXDEPTH=10 +FORUM_THREAD_CLEARCACHE_AFTER=30 # In Tagen +GALLERY_MAX_PIC_WIDTH=800 # In Pixel +GALLERY_MAX_PIC_HEIGHT=600 # In Pixel +GALLERY_MAX_THUMB_WIDTH=150 # In Pixel +GALLERY_MAX_THUMB_HEIGHT=150 # In Pixel +APOD_GALLERY_ID= # Match to gallery_albums-Table `id` +GO_OFFSET_PIC=250 # In Pixel +GO_LINKRADIUS=15 # In Pixel +GO_FIELDSIZE=40 # In Pixel +GO_LINEWIDTH=2 # In Pixel +GO_STARDOTWIDTH=10 # In Pixel +GO_STONEBIGWIDTH=190 # In Pixel +GO_LASTSTONEWIDTH=10 # In Pixel URLPATH_HZ_IMAGES="${URLPATH_IMAGES}hz/" HZ_MAPS_EXTENSION=".gif" -HZ_MAX_GAMES= -HZ_TURN_TIME= # In Sekunden: 3 Tage -HZ_TURN_COUNT= -HZ_TURN_ADD_MONEY= +HZ_MAX_GAMES=5 +HZ_TURN_TIME=259200 # In Sekunden: 3 Tage +HZ_TURN_COUNT=4 +HZ_TURN_ADD_MONEY=10 SETI_TEAM_NAME="" SETI_EMAIL="" STRING_NOT_FOUND="Reference not found in String list" @@ -124,8 +125,8 @@ COOKIE_USERPW="autologin_pw" SMARTY_CACHE="${APP_ROOT}/data/smartylib/cache/" SMARTY_COMPILE="${APP_ROOT}/data/smartylib/templates_c/" SMARTY_DIR="${WWW_ROOT}/smartylib/" -SMARTY_TRUSTED_DIRS="${WWW_ROOT}/scripts/" # (array) with strings -SMARTY_TEMPLATES_HTML="${VIEWS_DIR}" # (array) with strings +SMARTY_TRUSTED_DIRS="${WWW_ROOT}/scripts/" # Comma-separated list of paths +SMARTY_TEMPLATES_HTML="${VIEWS_DIR}" # Comma-separated list of paths SMARTY_PACKAGES_DIR="${WWW_ROOT}/packages/" SMARTY_PACKAGES_EXTENSION=".php" SMARTY_DEFAULT_TPL_ID= @@ -166,12 +167,12 @@ TELEGRAM_BOT="" # as registered with @BotFather TELEGRAM_BOT_API_KEY="" # as provided by @BotFather TELEGRAM_BOT_API="https://api.telegram.org/bot${TELEGRAM_BOT_API_KEY}/" TELEGRAM_BOT_API_AUTH_PASSWORD="" # (string) A secret password required to authorise access to the webhook -TELEGRAM_BOT_API_IPWHITELIST="[]" # (array) When using `validate_request`, like: [ '1.2.3.4', '1.1.1.1-2.2.2.2'] -TELEGRAM_BOT_API_USERWHITELIST="[]" # (array) An array of Telegram UserIDs that have admin access to your bot (must be integers) -TELEGRAM_BOT_API_SSLCERT_PATH="" # (string) Path to a self-signed certificate (if necessary), like: "/server.crt" +TELEGRAM_BOT_API_IPWHITELIST="" # (comma separated list) When using `validate_request`, like: 1.2.3.4,1.1.1.1-2.2.2.2 +TELEGRAM_BOT_API_USERWHITELIST="" # (comma separated list) A list of Telegram UserIDs that have admin access to your bot +TELEGRAM_BOT_API_SSLCERT_PATH="" # (string) Path to a self-signed certificate (if necessary), like: /server.crt TELEGRAM_BOT_API_CHAT="" # (integer) Chat-ID where the Telegram Bot will post to -TELEGRAM_BOT_API_FILES_DIR="" # (array) List of configurable paths. -TELEGRAM_BOT_API_LOG_DIR="${ERRORLOG_DIR}" # (array) Paths where the log files should be put. +TELEGRAM_BOT_API_FILES_DIR="" # Comma-separated list of paths. +TELEGRAM_BOT_API_LOG_DIR="${ERRORLOG_DIR}" # (string) Path to where the log files should be put. # - Twitter API TWITTER_API_KEY="" TWITTER_API_SECRET="" @@ -198,3 +199,6 @@ ZORG_VEREIN_KONTO_IBAN="CH7500781622431172000" ZORG_VEREIN_KONTO_IBAN_QRBILL="CH9730781622431172000" ZORG_VEREIN_KONTO_CURRENCY="CHF" ZORG_VEREIN_KONTO_BESRID="" + +# Local Development and Debugging settings: +DEBUG_SCOPE="" # (Optional) A File or Function name to debug diff --git a/.gitignore b/.gitignore index c735aed..b83f1da 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.log /vendor .env +*.code-workspace # ...and DON'T ignore these things !.github/ @@ -21,4 +22,3 @@ !/keys !/migration !/scripts -Docker/mysql57 diff --git a/Docker/.env.docker b/Docker/.env.docker index 41a426b..0c3da6e 100644 --- a/Docker/.env.docker +++ b/Docker/.env.docker @@ -1,18 +1,21 @@ # === Docker === COMPOSE_PROJECT_NAME="zorg" OS_PLATFORM="linux/x86_64" -HTTP_PORT="80" -HTTPS_PORT="443" +HTTP_PORT=80 +HTTPS_PORT=443 DOMAINNAME="zorg.local" APACHE_USER="www-data" APACHE_GROUP="www-data" APACHE_WEBROOT="/var/www" -PHP_Version="7.4" +PHP_Version=7.4 PHP_INI_DIR="/usr/local/etc/php" -MYSQL_VERSION="5.7" +XDEBUG_PORT=9003 +XDEBUG_MODES="develop,debug,profile" +XDEBUG_LOGLEVEL=7 +MYSQL_VERSION=5.7 MYSQL_LOCAL_DATABASE_PATH="./Docker/mysql57" -MYSQL_PORT="3306" +MYSQL_PORT=3306 MYSQL_DATABASE="zooomclan" MYSQL_USER="root" MYSQL_PASSWORD="" -PHPMYADMIN_PORT="8080" +PHPMYADMIN_PORT=8080 diff --git a/Docker/.gitignore b/Docker/.gitignore index 2f447d7..db9cc02 100644 --- a/Docker/.gitignore +++ b/Docker/.gitignore @@ -1,2 +1,5 @@ # Ignore changes within the Docker database volume -mysql57 +/mysql57 + +# ...and DON'T ignore the DB template +!/mysql57/zooomclan-empty diff --git a/Docker/README.md b/Docker/README.md index a8f5b8e..ce298b3 100644 --- a/Docker/README.md +++ b/Docker/README.md @@ -4,42 +4,17 @@ ## Docker configs Edit the file: `.env.docker` -### Using docker-sync -`docker-sync` greatly improves the performance of synced volumes from the local file system to Docker, giving a nearly live-performance for read/write operations. - #### Setup on macOS (The following steps are copied from [this online documentation](https://reece.tech/posts/osx-docker-performance/)) +* **Recommendation**: use [OrbStack](https://orbstack.dev/) instead of Docker Desktop for Mac! -##### Install docker-sync - -``` -gem install --user-install docker-sync -brew install fswatch -brew install unison -brew install eugenmayer/dockersync/unox -``` - -#### Configuring docker-sync -Docker sync requires a valid configuration file (docker-sync.yaml), the below file creates a named volume for Docker called osx-sync and mounts the local macOS directory. - -Add `docker-sync` to your $PATH using `nano ~/.zshrc` - -``` -if which ruby >/dev/null && which gem >/dev/null; then - PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH" -fi -``` - -Now run `source ~/.zshrc` to apply the $PATH settings. - -## Build the Docker container and docker-sync +## Build the Docker container & start the services Start container with all services. * in "detached mode" - without interative log in the Shell ``` cd /path/to/zorg-code/ -docker-sync start -c ./Docker/docker-sync.yml docker compose --project-directory ./ --file ./Docker/docker-compose.yml --env-file ./Docker/.env.docker up -d ``` @@ -47,7 +22,6 @@ docker compose --project-directory ./ --file ./Docker/docker-compose.yml --env-f ``` cd /path/to/zorg-code/ -docker-sync-stack start -c ./Docker/docker-sync.yml docker compose --project-directory ./ --file ./Docker/docker-compose.yml --env-file ./Docker/.env.docker up ``` @@ -122,6 +96,10 @@ Enter into interactive shell mode for a container service `docker exec -it SERVICENAME sh` +List all Environment Variables for a container service + +`docker exec SERVICENAME env` + ### docker-sync inspection !! Refresh docker-sync after updating the `docker-compose.yml`-file @@ -135,3 +113,76 @@ Inspect running docker-sync services: Inspect the logfile for sendmail / msmtprc: `docker exec -it zorg-web cat /var/log/sendmail.log` + + +## Archive / Deprecated +### Using docker-sync (not recommended!) +`docker-sync` greatly improves the performance of synced volumes from the local file system to Docker, giving a nearly live-performance for read/write operations. + +##### Install docker-sync + +``` +gem install --user-install docker-sync +brew install fswatch +brew install unison +brew install eugenmayer/dockersync/unox +``` + +#### Configuring docker-sync +Docker sync requires a valid configuration file (docker-sync.yaml), the below file creates a named volume for Docker called osx-sync and mounts the local macOS directory. + +Add `docker-sync` to your $PATH using `nano ~/.zshrc` + +``` +if which ruby >/dev/null && which gem >/dev/null; then + PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH" +fi +``` + +Now run `source ~/.zshrc` to apply the $PATH settings. + +##### Add `docker-sync.yml` to `/Docker/` dir +Here's an example `docker-sync` YAML configuration: + +```yaml +version: "2" +options: + config_path: './../' + compose-file-path: './docker-compose.yml' + verbose: true +syncs: +# sync_strategy: see https://docker-sync.readthedocs.io/en/latest/getting-started/configuration.html#sync-strategy + zorg-web-root-git-sync: + src: './.git' + sync_strategy: 'unison' + zorg-web-root-data-sync: + src: './data' + sync_strategy: 'unison' + #sync_excludes: [ ] + zorg-web-root-vendor-sync: + src: './vendor' + sync_strategy: 'unison' + # sync_host_ip: 'auto' + # sync_host_port: 10873 + sync_excludes: [ ] + zorg-web-root-www-sync: + src: './www' + sync_strategy: 'unison' + sync_excludes: [ ] + zorg-db-mysql-sync: + src: './Docker/mysql57' + sync_strategy: 'unison' + sync_excludes: [ ] + +``` + +#### Build the Docker container with docker-sync +Start container with all services. + +* in "detached mode" - without interative log in the Shell + +``` +cd /path/to/zorg-code/ +docker-sync start -c ./Docker/docker-sync.yml +docker compose --project-directory ./ --file ./Docker/docker-compose.yml --env-file ./Docker/.env.docker up -d +``` diff --git a/Docker/docker-compose.yml b/Docker/docker-compose.yml index 7392e57..1aa2868 100644 --- a/Docker/docker-compose.yml +++ b/Docker/docker-compose.yml @@ -1,7 +1,3 @@ -networks: - frontend: - driver: bridge - services: apache-php: platform: ${OS_PLATFORM} @@ -9,19 +5,30 @@ services: container_name: ${COMPOSE_PROJECT_NAME}-web restart: unless-stopped environment: - - APACHE_DOCUMENT_ROOT=${APACHE_WEBROOT:-/var/www} + APACHE_DOCUMENT_ROOT: ${APACHE_WEBROOT:-/var/www} #- APACHE_RUN_USER=${APACHE_USER:-www-data} # Causes issues with Session-Handling in /tmp #- APACHE_RUN_GROUP=${APACHE_GROUP:-www-data} # And causes issues with reading from ../.git + XDEBUG_CONFIG: > + mode=${XDEBUG_MODES:-develop,debug} + idekey=docker + client_port=${XDEBUG_PORT:-9003} + client_host=host.docker.internal + discover_client_host=true + start_with_request=yes + trigger_value=StartProfileForMe + log=/dev/stdout + log_level=${XDEBUG_LOGLEVEL:-0} hostname: webserver domainname: ${DOMAINNAME} - networks: - - frontend + extra_hosts: + - host.docker.internal:host-gateway ports: - ${HTTP_PORT:-80}:80 - ${HTTPS_PORT:-443}:443 expose: - - 80 - - 443 + - ${HTTP_PORT:-80} + - ${HTTPS_PORT:-443} + #- ${XDEBUG_PORT:-9003} # XDebug healthcheck: test: git --version || exit 1 interval: 20s @@ -34,17 +41,14 @@ services: - ./Docker/sendmail/msmtprc:/etc/apache2/sites-available/default-ssl.conf - ./.env:${APACHE_WEBROOT:?err}/.env - ./.git:${APACHE_WEBROOT:?err}/.git - #- web-root-git-sync:${APACHE_WEBROOT:?err}/.git:nocopy - ./cron:${APACHE_WEBROOT:?err}/cron - ./data:${APACHE_WEBROOT:?err}/data - #- web-root-data-sync:${APACHE_WEBROOT:?err}/data:nocopy Issue with modified Files not being synced - ./irclogs:${APACHE_WEBROOT:?err}/irclogs - ./keys:${APACHE_WEBROOT:?err}/keys - ./migration:${APACHE_WEBROOT:?err}/migration - ./scripts:${APACHE_WEBROOT:?err}/scripts - - web-root-vendor-sync:${APACHE_WEBROOT:?err}/vendor:nocopy + - ./vendor:${APACHE_WEBROOT:?err}/vendor - ./www:${APACHE_WEBROOT:?err}/html - #- web-root-www-sync:${APACHE_WEBROOT:?err}/html:nocopy Issue with modified Files not being synced entrypoint: ["/bin/sh","-c"] command: - | @@ -58,6 +62,7 @@ services: chmod +x /usr/local/bin/install-php-extensions && \ install-php-extensions mysqli pdo_mysql xdebug gd exif apt-get -y update && apt-get -y install git msmtp mailutils + git config --global safe.directory '*' grep -Fx -q 'Mutex posixsem' /etc/apache2/apache2.conf || echo 'Mutex posixsem' >> /etc/apache2/apache2.conf exec /usr/sbin/apache2ctl -D FOREGROUND # Additional install-php-extensions: intl, mbstring, gettext, curl, json, zip, exif @@ -75,8 +80,6 @@ services: #- MYSQL_USER=${MYSQL_USER-dbuser} #- MYSQL_PASSWORD=${MYSQL_PASSWORD-root} #- MYSQL_ROOT_HOST="%" # in some scenarios this revokes Host IP connection restrictions - networks: - - frontend ports: - ${MYSQL_PORT:-3306}:3306 expose: @@ -87,7 +90,7 @@ services: timeout: 3s retries: 5 volumes: - - db-mysql-sync:/var/lib/mysql:nocopy + - ./Docker/mysql57:/var/lib/mysql command: [mysqld, --default-authentication-plugin=mysql_native_password, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all, --max-connections=1001, --explicit_defaults_for_timestamp] db-manager: @@ -103,19 +106,5 @@ services: #- PMA_HOST=db #- MYSQL_USER={MYSQL_USER-root} # phpMyAdmin connects using the MySQL credentials env #- MYSQL_PASSWORD=${MYSQL_PASSWORD-root} # phpMyAdmin connects using the MySQL credentials env - networks: - - frontend ports: - ${PHPMYADMIN_PORT:-8080}:80 - -volumes: - #web-root-git-sync: - #external: true - #web-root-data-sync: - #external: true - #web-root-www-sync: - #external: true - web-root-vendor-sync: - external: true - db-mysql-sync: - external: true diff --git a/Docker/docker-sync.yml b/Docker/docker-sync.yml deleted file mode 100644 index 5f78fab..0000000 --- a/Docker/docker-sync.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: "2" -options: - config_path: './../' - compose-file-path: './docker-compose.yml' - verbose: true -syncs: -# sync_strategy: see https://docker-sync.readthedocs.io/en/latest/getting-started/configuration.html#sync-strategy - #zorg-web-root-git-sync: - #src: './.git' - #sync_strategy: 'unison' - #zorg-web-root-data-sync: - #src: './data' - #sync_strategy: 'unison' - #sync_excludes: [ ] - zorg-web-root-vendor-sync: - src: './vendor' - sync_strategy: 'unison' - # sync_host_ip: 'auto' - # sync_host_port: 10873 - sync_excludes: [ ] - #zorg-web-root-www-sync: - #src: './www' - #sync_strategy: 'unison' - #sync_excludes: [ ] - zorg-db-mysql-sync: - src: './Docker/mysql57' - sync_strategy: 'unison' - sync_excludes: [ ] diff --git a/Docker/php/xdebug.ini b/Docker/php/xdebug.ini new file mode 100644 index 0000000..eef36e7 --- /dev/null +++ b/Docker/php/xdebug.ini @@ -0,0 +1,11 @@ +zend_extension=xdebug + +[xdebug] +xdebug.mode=develop,debug#,profile,coverage +xdebug.idekey=docker +xdebug.client_host=host.docker.internal +xdebug.start_with_request=yes +xdebug.log=/dev/stdout +xdebug.log_level=0 +xdebug.client_port=9003 +xdebug.client_host=host.docker.internal diff --git a/composer.json b/composer.json index a873145..7868efc 100644 --- a/composer.json +++ b/composer.json @@ -6,9 +6,9 @@ } }, "require": { - "vlucas/phpdotenv": "^5.4", + "vlucas/phpdotenv": "^5.6", "sprain/swiss-qr-bill": "^3.2", - "maxmind-db/reader": "^1.0" + "maxmind-db/reader": "^1.11" }, "require-dev": { } diff --git a/composer.lock b/composer.lock index 13625a3..c8ade22 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d41fb2ef048358f4acc960bb71717d89", + "content-hash": "b0ea0a22d496f7c037dbbaaf93007190", "packages": [ { "name": "bacon/bacon-qr-code", @@ -62,16 +62,16 @@ }, { "name": "dasprid/enum", - "version": "1.0.4", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/DASPRiD/Enum.git", - "reference": "8e6b6ea76eabbf19ea2bf5b67b98e1860474012f" + "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8e6b6ea76eabbf19ea2bf5b67b98e1860474012f", - "reference": "8e6b6ea76eabbf19ea2bf5b67b98e1860474012f", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/6faf451159fb8ba4126b925ed2d78acfce0dc016", + "reference": "6faf451159fb8ba4126b925ed2d78acfce0dc016", "shasum": "" }, "require": { @@ -106,9 +106,9 @@ ], "support": { "issues": "https://github.com/DASPRiD/Enum/issues", - "source": "https://github.com/DASPRiD/Enum/tree/1.0.4" + "source": "https://github.com/DASPRiD/Enum/tree/1.0.5" }, - "time": "2023-03-01T18:44:03+00:00" + "time": "2023-08-25T16:18:39+00:00" }, { "name": "endroid/qr-code", @@ -187,24 +187,24 @@ }, { "name": "graham-campbell/result-type", - "version": "v1.1.1", + "version": "v1.1.2", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831" + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862", + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.1" + "phpoption/phpoption": "^1.9.2" }, "require-dev": { - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "type": "library", "autoload": { @@ -233,7 +233,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2" }, "funding": [ { @@ -245,7 +245,7 @@ "type": "tidelift" } ], - "time": "2023-02-25T20:23:15+00:00" + "time": "2023-11-12T22:16:48+00:00" }, { "name": "khanamiryan/qrcode-detector-decoder", @@ -355,23 +355,23 @@ }, { "name": "maxmind-db/reader", - "version": "v1.11.0", + "version": "v1.11.1", "source": { "type": "git", - "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", - "reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b" + "url": "git@github.com:maxmind/MaxMind-DB-Reader-php.git", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/b1f3c0699525336d09cc5161a2861268d9f2ae5b", - "reference": "b1f3c0699525336d09cc5161a2861268d9f2ae5b", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/1e66f73ffcf25e17c7a910a1317e9720a95497c7", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7", "shasum": "" }, "require": { "php": ">=7.2" }, "conflict": { - "ext-maxminddb": "<1.10.1,>=2.0.0" + "ext-maxminddb": "<1.11.1,>=2.0.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "3.*", @@ -412,11 +412,7 @@ "geolocation", "maxmind" ], - "support": { - "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", - "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.11.0" - }, - "time": "2021-10-18T15:23:10+00:00" + "time": "2023-12-02T00:09:23+00:00" }, { "name": "myclabs/php-enum", @@ -483,16 +479,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.1", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820", + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820", "shasum": "" }, "require": { @@ -500,7 +496,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "type": "library", "extra": { @@ -542,7 +538,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.2" }, "funding": [ { @@ -554,7 +550,7 @@ "type": "tidelift" } ], - "time": "2023-02-25T19:38:58+00:00" + "time": "2023-11-12T21:59:55+00:00" }, { "name": "sprain/swiss-qr-bill", @@ -687,16 +683,16 @@ }, { "name": "symfony/intl", - "version": "v5.4.23", + "version": "v5.4.30", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "962789bbc76c82c266623321ffc24416f574b636" + "reference": "cd6cce16151ac871071a3495e7a325460b952b5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/962789bbc76c82c266623321ffc24416f574b636", - "reference": "962789bbc76c82c266623321ffc24416f574b636", + "url": "https://api.github.com/repos/symfony/intl/zipball/cd6cce16151ac871071a3495e7a325460b952b5a", + "reference": "cd6cce16151ac871071a3495e7a325460b952b5a", "shasum": "" }, "require": { @@ -705,7 +701,8 @@ "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "symfony/filesystem": "^4.4|^5.0|^6.0" + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -755,7 +752,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v5.4.23" + "source": "https://github.com/symfony/intl/tree/v5.4.30" }, "funding": [ { @@ -771,7 +768,7 @@ "type": "tidelift" } ], - "time": "2023-04-13T10:36:25+00:00" + "time": "2023-10-28T09:19:54+00:00" }, { "name": "symfony/options-resolver", @@ -844,16 +841,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -868,7 +865,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -906,7 +903,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -922,20 +919,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354" + "reference": "875e90aeea2777b6f135677f618529449334a612" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", + "reference": "875e90aeea2777b6f135677f618529449334a612", "shasum": "" }, "require": { @@ -947,7 +944,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -987,7 +984,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" }, "funding": [ { @@ -1003,20 +1000,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c" + "reference": "e46b4da57951a16053cd751f63f4a24292788157" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/a3d9148e2c363588e05abbdd4ee4f971f0a5330c", - "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/e46b4da57951a16053cd751f63f4a24292788157", + "reference": "e46b4da57951a16053cd751f63f4a24292788157", "shasum": "" }, "require": { @@ -1028,7 +1025,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1074,7 +1071,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.28.0" }, "funding": [ { @@ -1090,20 +1087,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-03-21T17:27:24+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { @@ -1115,7 +1112,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1158,7 +1155,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" }, "funding": [ { @@ -1174,20 +1171,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -1202,7 +1199,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1241,7 +1238,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, "funding": [ { @@ -1257,20 +1254,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", "shasum": "" }, "require": { @@ -1279,7 +1276,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1320,7 +1317,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" }, "funding": [ { @@ -1336,20 +1333,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { @@ -1358,7 +1355,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1403,7 +1400,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" }, "funding": [ { @@ -1419,20 +1416,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", "shasum": "" }, "require": { @@ -1441,7 +1438,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1482,7 +1479,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" }, "funding": [ { @@ -1498,20 +1495,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/property-access", - "version": "v5.4.22", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "ffee082889586b5718347b291e04071f4d07b38f" + "reference": "0249e46f69e92049a488f39fcf531cb42c50caaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/ffee082889586b5718347b291e04071f4d07b38f", - "reference": "ffee082889586b5718347b291e04071f4d07b38f", + "url": "https://api.github.com/repos/symfony/property-access/zipball/0249e46f69e92049a488f39fcf531cb42c50caaa", + "reference": "0249e46f69e92049a488f39fcf531cb42c50caaa", "shasum": "" }, "require": { @@ -1563,7 +1560,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v5.4.22" + "source": "https://github.com/symfony/property-access/tree/v5.4.26" }, "funding": [ { @@ -1579,7 +1576,7 @@ "type": "tidelift" } ], - "time": "2023-03-14T14:59:20+00:00" + "time": "2023-07-13T15:20:41+00:00" }, { "name": "symfony/property-info", @@ -1674,16 +1671,16 @@ }, { "name": "symfony/string", - "version": "v5.4.22", + "version": "v5.4.32", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" + "reference": "91bf4453d65d8231688a04376c3a40efe0770f04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "url": "https://api.github.com/repos/symfony/string/zipball/91bf4453d65d8231688a04376c3a40efe0770f04", + "reference": "91bf4453d65d8231688a04376c3a40efe0770f04", "shasum": "" }, "require": { @@ -1740,7 +1737,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.22" + "source": "https://github.com/symfony/string/tree/v5.4.32" }, "funding": [ { @@ -1756,7 +1753,7 @@ "type": "tidelift" } ], - "time": "2023-03-14T06:11:53+00:00" + "time": "2023-11-26T13:43:46+00:00" }, { "name": "symfony/translation-contracts", @@ -1838,16 +1835,16 @@ }, { "name": "symfony/validator", - "version": "v5.4.24", + "version": "v5.4.32", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "47794a3cb530e01593ecad9856ba80f5c011e36b" + "reference": "d205d071c4a7ef5b6b43349c7e41d47d1b227636" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/47794a3cb530e01593ecad9856ba80f5c011e36b", - "reference": "47794a3cb530e01593ecad9856ba80f5c011e36b", + "url": "https://api.github.com/repos/symfony/validator/zipball/d205d071c4a7ef5b6b43349c7e41d47d1b227636", + "reference": "d205d071c4a7ef5b6b43349c7e41d47d1b227636", "shasum": "" }, "require": { @@ -1930,7 +1927,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v5.4.24" + "source": "https://github.com/symfony/validator/tree/v5.4.32" }, "funding": [ { @@ -1946,35 +1943,35 @@ "type": "tidelift" } ], - "time": "2023-05-25T13:05:00+00:00" + "time": "2023-11-29T07:42:18+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.5.0", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7" + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.0.2", - "php": "^7.1.3 || ^8.0", - "phpoption/phpoption": "^1.8", - "symfony/polyfill-ctype": "^1.23", - "symfony/polyfill-mbstring": "^1.23.1", - "symfony/polyfill-php80": "^1.23.1" + "graham-campbell/result-type": "^1.1.2", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.2", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "suggest": { "ext-filter": "Required to use the boolean validator." @@ -1986,7 +1983,7 @@ "forward-command": true }, "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "5.6-dev" } }, "autoload": { @@ -2018,7 +2015,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0" }, "funding": [ { @@ -2030,7 +2027,7 @@ "type": "tidelift" } ], - "time": "2022-10-16T01:01:54+00:00" + "time": "2023-11-12T22:43:29+00:00" } ], "packages-dev": [], @@ -2044,5 +2041,5 @@ "platform-overrides": { "php": "7.4" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000..61f7844 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1,18 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore +# -- INSTRUCTIONS --- +# Add to this folder the following directories +# /errlog +# /files +# /gallery +# /upload +# /smartylib +# /cache +# /templates_c +# /tauschboerse +# /upload +# /temp +# /upload +# /userimages diff --git a/data/errlog/.gitignore b/data/errlog/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/errlog/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/files/.gitignore b/data/files/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/files/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/gallery/.gitignore b/data/gallery/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/gallery/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/smartylib/.gitignore b/data/smartylib/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/smartylib/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/smartylib/cache/.gitignore b/data/smartylib/cache/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/smartylib/cache/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/smartylib/templates_c/.gitignore b/data/smartylib/templates_c/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/smartylib/templates_c/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/tauschboerse/.gitignore b/data/tauschboerse/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/tauschboerse/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/temp/.gitignore b/data/temp/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/temp/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/upload/.gitignore b/data/upload/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/upload/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/data/userimages/.gitignore b/data/userimages/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/data/userimages/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/www/.well-known/security.txt b/www/.well-known/security.txt index 4b45912..6b90943 100644 --- a/www/.well-known/security.txt +++ b/www/.well-known/security.txt @@ -9,4 +9,4 @@ Canonical: https://zorg.ch/.well-known/security.txt Canonical: https://zooomclan.org/.well-known/security.txt Hiring: https://zorg.ch/profil.php?do=anmeldung#newuser -Expires: 2023-12-23T23:23:23.000Z +Expires: 2024-12-23T23:23:23.000Z diff --git a/www/actions/chat_post.php b/www/actions/chat_post.php index 271e6d9..5ab8af3 100644 --- a/www/actions/chat_post.php +++ b/www/actions/chat_post.php @@ -5,7 +5,7 @@ $from_mobile = ($_POST['from_mobile'] != '' || $_POST['from_mobile'] > 0) ? 1 : 0 ; $chat_text = sanitize_userinput($_POST['text']); - $newBugId = $db->insert('chat', [ 'user_id' => $user->id, 'date' => 'NOW()', 'from_mobile' => $from_mobile, 'text' => $chat_text ], __FILE__, __LINE__, __METHOD__); + $newBugId = $db->insert('chat', [ 'user_id' => $user->id, 'date' => timestamp(true), 'from_mobile' => $from_mobile, 'text' => $chat_text ], __FILE__, __LINE__, __METHOD__); header('Location: '.base64url_decode($_POST['url'])); exit; diff --git a/www/actions/comment_new.php b/www/actions/comment_new.php index 8dc8a4b..8742943 100644 --- a/www/actions/comment_new.php +++ b/www/actions/comment_new.php @@ -8,19 +8,18 @@ /** * File Includes */ -//require_once __DIR__ .'/../includes/main.inc.php'; require_once dirname(__FILE__).'/../includes/forum.inc.php'; require_once INCLUDES_DIR.'usersystem.inc.php'; require_once INCLUDES_DIR.'util.inc.php'; -if(!($user->id > 0) || !is_numeric($user->id)) +if(!is_numeric($user->id) || $user->id <= 0) { http_response_code(403); // Set response code 403 (access denied) and exit. user_error('Du bist nicht eingeloggt.', E_USER_WARNING); die(); } -if($_POST['text'] == '' || empty($_POST['text']) || !isset($_POST['text'])) +if(!isset($_POST['text']) || $_POST['text'] == '' || empty($_POST['text'])) { http_response_code(400); // Set response code 400 (bad request) and exit. user_error('keine leeren Posts erlaubt.', E_USER_WARNING); @@ -29,7 +28,7 @@ $commentText = escape_text($_POST['text']); } -if($_POST['parent_id'] == '' || !is_numeric($_POST['parent_id'])) +if(!is_numeric($_POST['parent_id']) || $_POST['parent_id'] == '') { http_response_code(400); // Set response code 400 (bad request) and exit. user_error('Parent id leer oder ungültig: ' . $_POST['parent_id'], E_USER_WARNING); @@ -57,6 +56,8 @@ /** Remove any duplicate User-IDs */ $msg_users = array_unique($msg_users); +} else { + $msg_users = NULL; } /** Post new Comment & get Link */ diff --git a/www/actions/events.php b/www/actions/events.php index de755bb..4ea2ab5 100644 --- a/www/actions/events.php +++ b/www/actions/events.php @@ -27,7 +27,7 @@ if ( !empty($_POST['location'])) $eventLocation = sanitize_userinput($_POST['location']); if ( !empty($_POST['link'])) $eventLink = escape_text((filter_var($_POST['link'], FILTER_VALIDATE_URL)===false?(filter_var(SITE_PROTOCOL.$_POST['link'], FILTER_VALIDATE_URL)!==false?SITE_PROTOCOL.$_POST['link']:$error='Ungültiger Event-Link'):$_POST['link'])); if ( !empty($_POST['review_url'])) $eventReviewlink = escape_text((filter_var($_POST['review_url'], FILTER_VALIDATE_URL)===false?(filter_var(SITE_PROTOCOL.$_POST['review_url'], FILTER_VALIDATE_URL)!==false?SITE_PROTOCOL.$_POST['review_url']:$error='Ungültige Review-URL'):$_POST['review_url'])); -if ( !empty($_POST['description'])) $eventDescription = escape_text($_POST['description']); +if ( !empty($_POST['description'])) $eventDescription = sanitize_userinput($_POST['description']); if ( isset($_POST['gallery_id']) && is_numeric($_POST['gallery_id']) && $_POST['gallery_id'] >= 0) $eventGallery = $_POST['gallery_id']; if ( isset($_GET['join']) && is_numeric($_GET['join']) && $_GET['join'] >= 0) $eventJoinId = $_GET['join']; if ( isset($_GET['unjoin']) && is_numeric($_GET['unjoin']) && $_GET['unjoin'] >= 0) $eventUnjoinId = $_GET['unjoin']; @@ -58,7 +58,7 @@ ,"'.$_POST['endYear'].'-'.$_POST['endMonth'].'-'.$_POST['endDay'].' '.$_POST['endHour'].':00" ,'.$eventGallery.' ,'.$user->id.' - ,NOW() + ,'.timestamp(true).' ,"'.$eventReviewlink.'" )'; $idNewEvent = $db->query($sql, __FILE__, __LINE__, 'INSERT INTO events'); diff --git a/www/actions/forum_setboards.php b/www/actions/forum_setboards.php index d2a77a4..b1950b3 100644 --- a/www/actions/forum_setboards.php +++ b/www/actions/forum_setboards.php @@ -22,9 +22,9 @@ { $boards .= $_POST['boards'][$i].','; }*/ - $boards = escape_text(json_encode($_POST['forum_boards'])); - $sql = 'UPDATE user SET forum_boards = "'.$boards.'" WHERE id = '.$user->id; - $db->query($sql, __FILE__, __LINE__, 'SET forum_boards'); + $boards = json_encode($_POST['forum_boards']); + $sql = 'UPDATE user SET forum_boards=? WHERE id=?'; + $db->query($sql, __FILE__, __LINE__, 'SET forum_boards', [$boards, $user->id]); } header("Location: /forum.php"); diff --git a/www/actions/poll_edit.php b/www/actions/poll_edit.php index 1da6462..a97c80b 100644 --- a/www/actions/poll_edit.php +++ b/www/actions/poll_edit.php @@ -39,7 +39,7 @@ 'text' => sanitize_userinput($frm['text']) ,'user' => $user->id ,'type' => sanitize_userinput($frm['type']) - ,'date' => 'NOW()' + ,'date' => timestamp(true) ], __FILE__, __LINE__, 'INSERT INTO polls'); if (false === $newPollId || $newPollId <= 0) { diff --git a/www/actions/rezepte.php b/www/actions/rezepte.php index e2ffd23..15a4a14 100644 --- a/www/actions/rezepte.php +++ b/www/actions/rezepte.php @@ -31,7 +31,7 @@ ,'.(int)$_POST['difficulty'].' ,"'.$_POST['description'].'" ,'.$user->id.' - ,NOW() + ,'.timestamp(true).' )'; $rezeptId = $db->query($sql, __FILE__, __LINE__); header('Location: '.base64url_decode($_POST['url']).'&rezept_id='.$rezeptId); diff --git a/www/actions/stockbroker.php b/www/actions/stockbroker.php index 9d0d5a0..a8020d7 100644 --- a/www/actions/stockbroker.php +++ b/www/actions/stockbroker.php @@ -1,14 +1,13 @@ -id, $_POST['symbol'], $_POST['comparison'], $_POST['kurs'])) { header("Location: /?tpl=164"); } @@ -17,8 +16,8 @@ // Kaufen --------------------------------------------------------------------- -if($_POST['action'] == 'buy') { - if(Stockbroker::buyStock($user->id, $_POST['symbol'], $_POST['menge'], $_POST['max'])) { +if($_POST['action'] == 'buy') { + if(Stockbroker::buyStock($user->id, $_POST['symbol'], $_POST['menge'], $_POST['max'])) { header("Location: /?tpl=164"); } exit; @@ -27,11 +26,8 @@ // Verkaufen ------------------------------------------------------------------ if($_POST['action'] == 'sell') { - if(Stockbroker::sellStock($user->id, $_POST['symbol'], $_POST['menge'], $_POST['max'])) { + if(Stockbroker::sellStock($user->id, $_POST['symbol'], $_POST['menge'], $_POST['max'])) { header("Location: /?tpl=164"); } exit; } - - -?> \ No newline at end of file diff --git a/www/actions/tauschboerse.php b/www/actions/tauschboerse.php index 3ea32dc..f476725 100644 --- a/www/actions/tauschboerse.php +++ b/www/actions/tauschboerse.php @@ -1,8 +1,8 @@ id.' - ,NOW() + ,'.timestamp(true).' ,"'.$_POST['bezeichnung'].'" ,"'.$_POST['wertvorstellung'].'" ,"'.$_POST['zustand'].'" @@ -39,7 +39,7 @@ )'; $artikelId = $db->query($sql, __FILE__, __LINE__); - /** Falls ein Bild gewählt wurde. */ + /** Falls ein Bild gewählt wurde. */ if ($_FILES['image']['name']) { if($_FILES['image']['error'] != 0) { @@ -76,7 +76,7 @@ break; /** - * Archive an old Tauschbörse Angebot + * Archive an old Tauschbörse Angebot */ case 'archive': $artikelId = (int)$_GET['artikel_id']; diff --git a/www/actions/tpleditor.php b/www/actions/tpleditor.php index e625a1b..7d0c4a1 100644 --- a/www/actions/tpleditor.php +++ b/www/actions/tpleditor.php @@ -41,16 +41,16 @@ if (!smarty_brackets_ok($frm['tpl'], $brack_err)) $error .= $brack_err; - /** @FIXME deaktiviert bis ein besserer syntax checker gebaut ist. (biko) + // FIXME deaktiviert bis ein besserer syntax checker gebaut ist. (biko) /* $syntaxerr = smarty_remove_invalid_html($frm['tpl']); - if ($syntaxerr) $error .= "
HTML Syntax Error: $syntaxerr
"; + if ($syntaxerr) $error .= "
HTML Syntax Error: $syntaxerr
"; */ - if (!$error) + if (empty($error) || !$error) { $frm['id'] = htmlentities($frm['id'], ENT_QUOTES); - $frm['tpl'] = escape_text($frm['tpl']); + $frm['tpl'] = $frm['tpl']; $frm['title'] = sanitize_userinput($frm['title']); $frm['sidebar_tpl'] = (empty($frm['sidebar_tpl']) ? 'NULL' : htmlentities($frm['sidebar_tpl'], ENT_QUOTES)); $frm['page_title'] = htmlentities($frm['page_title'], ENT_NOQUOTES); @@ -73,10 +73,11 @@ ,'write_rights' => $frm['write_rights'] ,'sidebar_tpl' => $frm['sidebar_tpl'] ,'allow_comments' => $frm['allow_comments'] + ,'error' => null ,'owner' => $user->id ,'update_user' => $user->id - ,'created' => 'NOW()' - ,'last_update' => 'NOW()' + ,'created' => timestamp(true) + ,'last_update' => timestamp(true) ], __FILE__, __LINE__, 'Add new Template'); if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> New Template ID: %s', __FILE__, __LINE__, $frm['id'])); @@ -84,10 +85,11 @@ if ($frm['id'] > 0 && $frm['id'] != false) { Thread::setRights('t', $frm['id'], $frm['read_rights']); - $db->query('INSERT INTO templates_backup SELECT * FROM templates WHERE id='.$frm['id'], __FILE__, __LINE__, 'Copy Template to templates_backup'); + $db->query('INSERT INTO templates_backup SELECT * FROM templates WHERE id=?', __FILE__, __LINE__, 'Copy Template to templates_backup', [$frm['id']]); $updated_tplid = $frm['id']; $return_url = '/?tpl='.$updated_tplid; + $return_url .= '&created'; $smarty->assign('tplupdnew', 1); $state = t('created', 'tpl', $frm['id']); @@ -104,7 +106,7 @@ */ } elseif ($frm['id'] > 0) { /** Backup current version */ - $db->query('REPLACE INTO templates_backup SELECT * FROM templates WHERE id='.$frm['id'].' AND UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(last_update) > (60*60*24*3)', __FILE__, __LINE__, 'REPLACE INTO templates_backup'); + $db->query('REPLACE INTO templates_backup SELECT * FROM templates WHERE id=? AND UNIX_TIMESTAMP(?)-UNIX_TIMESTAMP(last_update) > (60*60*24*3)', __FILE__, __LINE__, 'REPLACE INTO templates_backup', [$frm['id'], timestamp(true)]); /*if ($frm['word']) $set_word = ', word="'.$frm['word'].'"';*/ $templateUpdateParams = [ @@ -116,10 +118,10 @@ ,'write_rights' => $frm['write_rights'] ,'sidebar_tpl' => $frm['sidebar_tpl'] ,'allow_comments' => $frm['allow_comments'] - ,'error' => '' + ,'error' => null ,'owner' => $user->id ,'update_user' => $user->id - ,'last_update' => 'NOW()' + ,'last_update' => timestamp(true) ]; if ($frm['word']) $templateUpdateParams = array_merge($templateUpdateParams, ['word' => $frm['word']]); if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> Update Template SQL-Params: %s', __FILE__, __LINE__, print_r($templateUpdateParams,true))); @@ -128,10 +130,10 @@ if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> Template ID #%d updated', __FILE__, __LINE__, $frm['id'])); } - if (!$error && $frm['id'] > 0) + if ((empty($error) || !$error) && $frm['id'] > 0) { /** Menus: remove all links between Template & Menus, relink selected Menus */ - $db->query('DELETE FROM tpl_menus WHERE tpl_id ='.$frm['id']); // delete all + $db->query('DELETE FROM tpl_menus WHERE tpl_id=?', __FILE__, __LINE__, 'DELETE FROM tpl_menus', [$frm['id']]); if (!empty($_POST['frm']['menus'])) { $tplmenusInsertData = null; @@ -145,7 +147,7 @@ } /** Packages: remove all links between Template & Packages, relink selected Packages */ - $db->query('DELETE FROM tpl_packages WHERE tpl_id ='.$frm['id']); // delete all + $db->query('DELETE FROM tpl_packages WHERE tpl_id=?', __FILE__, __LINE__, 'DELETE FROM tpl_packages', [$frm['id']]); if (!empty($_POST['frm']['packages'])) { $tplpackagesInsertData = null; @@ -169,34 +171,38 @@ * @since 1.0 `[z]biko` procedure added intially * @since 2.0 `03.01.2019` `IneX` Fixed Bug #768: must also recompile template based on /page/word (not only /tpl/id ) */ - if (!$error) + if (empty($error) || !$error) { /** Compile Templated - TPL-ID based */ //if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile() $frm: %s', __FILE__, __LINE__, print_r($frm,true))); if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(%s)', __FILE__, __LINE__, 'tpl:'.$frm['id'])); - if (!$smarty->compile('tpl:'.$frm['id'], $compile_err)) - { - for ($i=0; $i"; - } - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(tpl): ERROR (%s)', __FILE__, __LINE__, $error)); - } else { - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(tpl): SUCCESS', __FILE__, __LINE__)); - } - - /** Compile Templated - TPL-Word based (if applicable) */ - if (!empty($frm['word'])) - { - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(%s)', __FILE__, __LINE__, 'word:'.$frm['word'])); - if (!$smarty->compile('word:'.$frm['word'], $compile_err)) + try { + if (!$smarty->compile('tpl:'.$frm['id'], $compile_err)) { for ($i=0; $i"; + $error .= "
".$compile_err[$i]."
"; } - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(word): ERROR (%s)', __FILE__, __LINE__, $error)); + if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(tpl): ERROR (%s)', __FILE__, __LINE__, $error)); } else { - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(word): SUCCESS', __FILE__, __LINE__)); + if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(tpl): SUCCESS', __FILE__, __LINE__)); + } + + /** Compile Templated - TPL-Word based (if applicable) */ + if (!empty($frm['word'])) + { + if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(%s)', __FILE__, __LINE__, 'word:'.$frm['word'])); + if (!$smarty->compile('word:'.$frm['word'], $compile_err)) + { + for ($i=0; $i"; + } + if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(word): ERROR (%s)', __FILE__, __LINE__, $error)); + } else { + if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $smarty-compile(word): SUCCESS', __FILE__, __LINE__)); + } } + } catch (Exception $e) { + $error .= '
Exception in $smarty->compile(): ' . $e->getMessage() . '
'; } /** If compile-error, write it to the template in the DB */ @@ -207,16 +213,16 @@ } /** If everything worked well - ie. no Errors... */ - if (!$error) + if (empty($error) || !$error) { /** Unlock Template for editing - only if no $error occurred */ tpleditor_unlock($updated_tplid); if (!isset($return_url) || empty($return_url)) $return_url = '/?tpl='.$updated_tplid; + $return_url .= '&updated'; $updated_tplid = null; $enable_tpleditor = null; - // FIXME http://zorg.local/actions/tpleditor.php?tpl=17&tpleditor=1&tplupd=new => weisse Seite if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> header(Location): %s', __FILE__, __LINE__, $return_url)); header('Location: '.$return_url); exit(); @@ -227,7 +233,7 @@ $frm['tpl'] = stripslashes(stripslashes($frm['tpl'])); $frm['title'] = stripslashes(stripslashes($frm['title'])); $frm['packages'] = stripslashes(stripslashes($frm['packages'])); - /** @FIXME aus irgend einem grund ist stripslashes() 2x nötig. sonst wird nur ein teil der slashes entfernt. wüsste gern wieso. ([z]biko) */ + // FIXME aus irgend einem grund ist stripslashes() 2x nötig. sonst wird nur ein teil der slashes entfernt. wüsste gern wieso. ([z]biko) /** Pass $error to error-log */ error_log($error); diff --git a/www/gallery.php b/www/gallery.php index f24c2fd..a46f015 100644 --- a/www/gallery.php +++ b/www/gallery.php @@ -64,8 +64,7 @@ if (!empty($_GET['do'])) { $doAction = (string)$_GET['do']; - /** Das Benoten (und mypic markieren) können nebst Schönen auch die registrierten User, - deshalb müssen wirs vorziehen... */ + /** Das Benoten (und mypic markieren) können nebst Schönen auch die registrierten User, deshalb müssen wirs vorziehen... */ if ($user->is_loggedin() && ($doAction === 'benoten' || $doAction === 'mypic') && isset($_POST['picID']) && !empty($_POST['picID']) && $_POST['picID'] > 0) { switch ($doAction) @@ -96,10 +95,10 @@ $res = doEditAlbum($album_id, $_POST['frm']); if (!$album_id) $album_id = $res['id']; break; - case 'editAlbumFromEvent': - $res = doEditAlbumFromEvent($album_id, $_POST['event']); - if (!$album_id) $album_id = $res['id']; - break; + // case 'editAlbumFromEvent': NOT IMPLEMENTED + // $res = doEditAlbumFromEvent($album_id, $_POST['event']); + // if (!$album_id) $album_id = $res['id']; + // break; case 'delAlbum': $res = doDelAlbum($album_id, $_POST['del']); $_GET['show'] = $res['show']; diff --git a/www/includes/addle.inc.php b/www/includes/addle.inc.php index 319f858..6800e1e 100644 --- a/www/includes/addle.inc.php +++ b/www/includes/addle.inc.php @@ -201,7 +201,7 @@ function _update_dwz($user_id) { $e = $db->query('SELECT score FROM addle_dwz WHERE user='.$d['player2'], __FILE__, __LINE__, __FUNCTION__); $d2 = $db->fetch($e); if ($d2) { - $dwz2 = $d2[score]; + $dwz2 = $d2['score']; $prev_score_2 = $dwz2; } else $dwz2 = ADDLE_BASE_POINTS; @@ -336,7 +336,7 @@ function evil_max($game_data_array, $row, $score_self, $score_chind, $depth, $mo $game_data_array[$row*8 + $to_select] = "."; } else $game_data_array[$row + $to_select*8] = "."; - $new_data['game_data'] = join($game_data_array, ""); + $new_data['game_data'] = join($game_data_array, null); $new_data['row'] = $to_select; $new_data['score'] = ($score_self + ord($row_data[$to_select])) - 96; @@ -450,7 +450,7 @@ function evil_min($game_data_array, $row, $score_self, $score_chind, $depth, $mo nextturn = '.$new_nextturn.', nextrow = "'.$new_data['row'].'", '.$my_score.' = '.$new_data['score'].', - date = NOW()'; + date = '.timestamp(true); if($new_data['row'] != 23) { $sql_add = ''; } else { diff --git a/www/includes/apod.inc.php b/www/includes/apod.inc.php index 68e3833..a2cbd49 100644 --- a/www/includes/apod.inc.php +++ b/www/includes/apod.inc.php @@ -38,21 +38,15 @@ * * @author [z]biko * @author IneX - * @version 4.0 + * @version 4.1 * @since 1.0 `01.01.2004` function added * @since 2.0 `06.08.2018` function refactored to use NASA APOD API * @since 3.0 `09.08.2018` enhanced function so an APOD date can be passed * @since 4.0 `14.09.2018` added processing of videos & website links passed from the APOD API + * @since 4.1 `26.06.2023` fixes code quality issue "Unreachable code ('cleanup:')" * - * @uses APOD_API - * @uses APOD_TEMP_IMGPATH - * @uses APOD_GALLERY_ID - * @var $MAX_PIC_SIZE - * @uses cURLfetchJSON() - * @uses createPic() - * @uses getYoutubeVideoThumbnail() - * @uses getVimeoVideoThumbnail() - * @uses Comment::post() + * @uses APOD_API, APOD_TEMP_IMGPATH, APOD_GALLERY_ID, $MAX_PIC_SIZE + * @uses cURLfetchJSON(), createPic(), getYoutubeVideoThumbnail(), getVimeoVideoThumbnail(), Comment::post() * @param string $apod_date (Optional) A valid date after June 16 1995, formatted as: yyyy-mm-dd (2018-08-06) * @global object $db Globales Class-Object mit allen MySQL-Methoden * @global array $MAX_PIC_SIZE Globales Array im Scope von gallery.inc.php mit den Image-Width & -Height Grössen für Pics und Thumbnails @@ -107,8 +101,8 @@ function get_apod($apod_date_input=NULL) if ($new_apod_fileext === 'html') $new_apod_mediatype = 'website'; /** Check if APOD is not already fetched... */ - $sql = 'SELECT id, name, extension, pic_added FROM gallery_pics WHERE album = '.APOD_GALLERY_ID.' AND DATE(pic_added) = "'.$new_apod_date.'"'; - $checkTodaysAPOD = $db->fetch($db->query($sql, __FILE__, __LINE__, __FUNCTION__)); + $sql = 'SELECT id, name, extension, pic_added FROM gallery_pics WHERE album = ? AND DATE(pic_added) = ?'; + $checkTodaysAPOD = $db->fetch($db->query($sql, __FILE__, __LINE__, __FUNCTION__, [APOD_GALLERY_ID, $new_apod_date])); if (empty($checkTodaysAPOD['name']) || strpos($checkTodaysAPOD['name'], $new_apod_title) === false) { /** Save new APOD to the gallery_pics database table */ @@ -119,7 +113,7 @@ function get_apod($apod_date_input=NULL) 'album'=>APOD_GALLERY_ID ,'extension'=>$new_apod_fileext ,'pic_added'=>$new_apod_date - ,'name'=>escape_text($new_apod_title.($new_apod_mediatype == 'video' ? ' [video]' : '')) + ,'name'=>$new_apod_title.($new_apod_mediatype == 'video' ? ' [video]' : '') ], __FILE__, __LINE__, __FUNCTION__); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> $new_apod_picid: %s', __FUNCTION__, __LINE__, $new_apod_picid)); @@ -137,7 +131,11 @@ function get_apod($apod_date_input=NULL) /** APOD media_type is 'image'... */ case 'image': /** Fetch and save the APOD image to APOD_TEMP_IMGPATH */ - if (!cURLfetchUrl($new_apod_img_small, $new_apod_temp_filepath)) goto cleanup; + if (!cURLfetchUrl($new_apod_img_small, $new_apod_temp_filepath)) + { + remove_apod_id_from_db($new_apod_picid); + return false; + } /** Filepfade zum finalen Speicherort des aktuellen APOD-Bildes (Original & Thumbnail) */ $new_apod_filepath_pic = picPath(APOD_GALLERY_ID, $new_apod_picid, $new_apod_fileext); // Fix eventual double-slashes in path @@ -147,18 +145,20 @@ function get_apod($apod_date_input=NULL) if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> createPic(): %s', __FUNCTION__, __LINE__, $new_apod_filepath_pic)); if (!createPic($new_apod_temp_filepath, $new_apod_filepath_pic, $MAX_PIC_SIZE['picWidth'], $MAX_PIC_SIZE['picHeight'])) { - error_log(sprintf('<%s:%d> %s createPic() ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic)); + error_log(sprintf('[ERROR] <%s:%d> %s createPic() ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic)); /** Goto: cleanup */ - goto cleanup; + remove_apod_id_from_db($new_apod_picid); + return false; } /** Create APOD gallery pic-thumbnail */ if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> createPic() thumbnail: %s', __FUNCTION__, __LINE__, $new_apod_filepath_pic_tn)); if (!createPic($new_apod_temp_filepath, $new_apod_filepath_pic_tn, $MAX_PIC_SIZE['tnWidth'], $MAX_PIC_SIZE['tnHeight'])) { - error_log(sprintf('<%s:%d> %s createPic() thumbnail ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic_tn)); + error_log(sprintf('[ERROR] <%s:%d> %s createPic() thumbnail ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic_tn)); /** Goto: cleanup */ - goto cleanup; + remove_apod_id_from_db($new_apod_picid); + return false; } /** Regular cleanup: remove temp-file from APOD_TEMP_IMGPATH */ @@ -197,28 +197,37 @@ function get_apod($apod_date_input=NULL) if (empty($media_type) || is_array($media_type)) { /** Goto: cleanup */ - goto cleanup; + remove_apod_id_from_db($new_apod_picid); + return false; } else { /** Get Video-Thumbnail image */ $new_apod_img_thumbnail = getVideoThumbnail($media_type, $new_apod_urlparts['filename']); $new_apod_temp_filepath = $new_apod_temp_filepath.pathinfo($new_apod_img_thumbnail, PATHINFO_EXTENSION); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> cURLfetchUrl(): %s', __FUNCTION__, __LINE__, $new_apod_temp_filepath)); - if (!cURLfetchUrl($new_apod_img_thumbnail, $new_apod_temp_filepath)) goto cleanup; + if (!cURLfetchUrl($new_apod_img_thumbnail, $new_apod_temp_filepath)) + { + remove_apod_id_from_db($new_apod_picid); + return false; + } /** Create APOD gallery pic-thumbnail for 'video' */ $new_apod_filepath_pic_tn = tnPath(APOD_GALLERY_ID, $new_apod_picid, '.'.pathinfo($new_apod_img_thumbnail, PATHINFO_EXTENSION)); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> createPic() thumbnail: %s', __FUNCTION__, __LINE__, $new_apod_filepath_pic_tn)); if (!createPic($new_apod_temp_filepath, $new_apod_filepath_pic_tn, $MAX_PIC_SIZE['tnWidth'], $MAX_PIC_SIZE['tnHeight'])) { - error_log(sprintf('<%s:%d> %s createPic() thumbnail ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic_tn)); - goto cleanup; + error_log(sprintf('[ERROR] <%s:%d> %s createPic() thumbnail ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic_tn)); + remove_apod_id_from_db($new_apod_picid); + return false; } /** Update APOD 'video' entry in gallery_pics table */ $result = $db->update('gallery_pics', ['id', $new_apod_picid], ['extension' => $media_type, 'picsize' => $new_apod_img_small], __FILE__, __LINE__, __FUNCTION__); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> $db->update(gallery_pics): (%s) %s', __FUNCTION__, __LINE__, $result, ($result>0 ? 'true' : 'false'))); - if ($result === 0) goto cleanup; + if ($result === 0) { + remove_apod_id_from_db($new_apod_picid); + return false; + } } break; @@ -234,22 +243,27 @@ function get_apod($apod_date_input=NULL) if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> createPic() thumbnail: %s', __FUNCTION__, __LINE__, $new_apod_filepath_pic_tn)); if (!createPic($new_apod_temp_filepath, $new_apod_filepath_pic_tn, $MAX_PIC_SIZE['tnWidth'], $MAX_PIC_SIZE['tnHeight'])) { - error_log(sprintf('<%s:%d> %s createPic() thumbnail ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic_tn)); - goto cleanup; + error_log(sprintf('[ERROR] <%s:%d> %s createPic() thumbnail ERROR: %s', __FILE__, __LINE__, __FUNCTION__, $new_apod_filepath_pic_tn)); + remove_apod_id_from_db($new_apod_picid); + return false; } /** Update APOD 'website' entry in gallery_pics table */ $result = $db->update('gallery_pics', ['id', $new_apod_picid], ['extension' => $new_apod_mediatype, 'picsize' => $new_apod_img_small], __FILE__, __LINE__, __FUNCTION__); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> $db->update(gallery_pics): (%s) %s', __FUNCTION__, __LINE__, $result, ($result>0 ? 'true' : 'false'))); - if ($result === 0) goto cleanup; + if ($result === 0) { + remove_apod_id_from_db($new_apod_picid); + return false; + } break; /** - * If APOD media_type is unsupported, goto cleanup + * APOD media_type is unsupported, goto cleanup */ default: - error_log(sprintf('<%s:%d> APOD has an unsupported media_type: %s', __FUNCTION__, __LINE__, $new_apod_mediatype)); - goto cleanup; + error_log(sprintf('[NOTICE] <%s:%d> APOD has an unsupported media_type: %s', __FUNCTION__, __LINE__, $new_apod_mediatype)); + remove_apod_id_from_db($new_apod_picid); + return false; } /** @@ -260,11 +274,6 @@ function get_apod($apod_date_input=NULL) $new_apod_comment = t('apod-pic-comment', 'apod', [ (!empty($new_apod_img_large) ? $new_apod_img_large : $new_apod_img_small), $new_apod_title, $new_apod_explanation, $new_apod_archive_url, (!empty($new_apod_copyright) ? $new_apod_copyright : $new_apod_archive_url) ]); Comment::post($new_apod_picid, 'i', BARBARA_HARRIS, $new_apod_comment); return true; - - /** Goto cleanup: on createPic=FALSE this goto will Cleanup & DELETE DB-Entry */ - cleanup: - $deleteFromGalleryPics = $db->query('DELETE FROM gallery_pics WHERE id = ' . $new_apod_picid, __FILE__, __LINE__, __FUNCTION__); - return false; } /** ...APOD is already fetched! */ @@ -282,9 +291,14 @@ function get_apod($apod_date_input=NULL) /** - * Aktuelleste APOD Bild-ID + * Aktuelleste APOD Bild-ID. * Holt das aktuellste APOD Bild aus der Datenbank * + * @version 2.1 + * @since 1.0 function added + * @since 2.0 function refactored + * @since 2.1 SQL uses prepared statement (mitigates possible SQL-Injection vulnerability) + * * @global object $db Globales Class-Object mit allen MySQL-Methoden * @return array DB-Query Result als Resource (Array) */ @@ -292,6 +306,32 @@ function get_apod_id() { global $db; - $sql = 'SELECT * FROM gallery_pics WHERE album = '.APOD_GALLERY_ID.' ORDER by id DESC LIMIT 0,1'; - return $db->fetch($db->query($sql)); + $sql = 'SELECT * FROM gallery_pics WHERE album = ? ORDER by id DESC LIMIT 1'; + return $db->fetch($db->query($sql, __FILE__, __LINE__, __FUNCTION__, [APOD_GALLERY_ID])); +} + + +/** + * APOD Pic-ID aus DB entfernen. + * Deletes the specified APOD Pic ID from the database and returns false + * + * @version 1.0 function added + * + * @param object $db Globales Class-Object mit allen MySQL-Methoden + * @param int $apod_picid ID of the APOD pic record to delete + * @return bool + */ +function remove_apod_id_from_db($apod_picid) +{ + global $db; + + /** Validate if $apod_picid is a valid integer and greater than 0 */ + if (filter_var($apod_picid, FILTER_VALIDATE_INT) && $apod_picid > 0) + { + $sql = 'DELETE FROM gallery_pics WHERE id = ?'; + $deleteFromGalleryPics = $db->query($sql, __FILE__, __LINE__, __FUNCTION__, [$apod_picid]); + return $deleteFromGalleryPics; + } + /** Return false if $apod_picid is invalid */ + return false; } diff --git a/www/includes/bugtracker.inc.php b/www/includes/bugtracker.inc.php index e33629a..c50a190 100644 --- a/www/includes/bugtracker.inc.php +++ b/www/includes/bugtracker.inc.php @@ -72,7 +72,7 @@ static function execActions() ,'priority' => $bugPriority ,'title' => $bugTitle ,'description' => $bugDescription - ,'reported_date' => 'NOW()' + ,'reported_date' => timestamp(true) ], __FILE__, __LINE__, __METHOD__); /** Activity Eintrag auslösen */ @@ -101,7 +101,7 @@ static function execActions() $rs = Bugtracker::getBugRS($bugId); if($rs['assignedto_id'] == 0) { - $result = $db->update('bugtracker_bugs', $bugId, ['assignedto_id' => $user->id, 'assigned_date' => 'NOW()'], __FILE__, __LINE__, __METHOD__); + $result = $db->update('bugtracker_bugs', $bugId, ['assignedto_id' => $user->id, 'assigned_date' => timestamp(true)], __FILE__, __LINE__, __METHOD__); } header('Location: '.(!empty($sanitizedReturnURL) ? $sanitizedReturnURL : '/bugtracker.php')); exit; @@ -114,7 +114,7 @@ static function execActions() $rs = Bugtracker::getBugRS($bugId); if($rs['assignedto_id'] == 0 OR $rs['assignedto_id'] > 0) { - $result = $db->update('bugtracker_bugs', $bugId, ['assignedto_id' => $user->id, 'assigned_date' => 'NOW()'], __FILE__, __LINE__, __METHOD__); + $result = $db->update('bugtracker_bugs', $bugId, ['assignedto_id' => $user->id, 'assigned_date' => timestamp(true)], __FILE__, __LINE__, __METHOD__); } header('Location: '.(!empty($sanitizedReturnURL) ? $sanitizedReturnURL : '/bugtracker.php')); exit; @@ -153,7 +153,7 @@ static function execActions() elseif (isset($_GET['action']) && $_GET['action'] === 'resolve') { $bugId = ( isset($_GET['bug_id']) && is_numeric($_GET['bug_id']) && $_GET['bug_id'] >= 0 ? (int)$_GET['bug_id'] : user_error('Bugtracker: invalid Bug-ID "' . $_GET['bug_id'] . '"', E_USER_WARNING) ); - $result = $db->update('bugtracker_bugs', $bugId, ['resolved_date' => 'NOW()'], __FILE__, __LINE__, __METHOD__); + $result = $db->update('bugtracker_bugs', $bugId, ['resolved_date' => timestamp(true)], __FILE__, __LINE__, __METHOD__); $rs = Bugtracker::getBugRS($bugId); /** Activity Eintrag auslösen */ @@ -199,7 +199,7 @@ static function execActions() elseif (isset($_GET['action']) && $_GET['action'] == 'deny') { $bugId = ( isset($_GET['bug_id']) && is_numeric($_GET['bug_id']) && $_GET['bug_id'] >= 0 ? (int)$_GET['bug_id'] : user_error('Bugtracker: invalid Bug-ID "' . $_GET['bug_id'] . '"', E_USER_WARNING) ); - $result = $db->update('bugtracker_bugs', $bugId, ['denied_date' => 'NOW()'], __FILE__, __LINE__, __METHOD__); + $result = $db->update('bugtracker_bugs', $bugId, ['denied_date' => timestamp(true)], __FILE__, __LINE__, __METHOD__); $rs = Bugtracker::getBugRS($bugId); /** Activity Eintrag auslösen */ diff --git a/www/includes/comments.fnc.php b/www/includes/comments.fnc.php index 952c2ab..ef7bd63 100644 --- a/www/includes/comments.fnc.php +++ b/www/includes/comments.fnc.php @@ -46,35 +46,39 @@ function smarty_base64_encode ($params) { } function smarty_comment_extend_depth ($params) { - global $smarty; - + global $smarty; + if (isset($params['depth'])) $depth = $params['depth']; - else $depth = array(); - - + else $depth = array(); + + if ($params['childposts'] > $params['rcount']) { array_push($depth, "vertline"); } else { array_push($depth, "space"); } $smarty->assign("hdepth", $depth); - + return ""; } function smarty_comment_remove_depth ($params) { global $smarty; - + $depth = $params['depth']; - + array_pop($depth); $smarty->assign("hdepth", $depth); - + return ""; } +/** + * Mark an unread comment as READ. + * return void + */ function smarty_comment_mark_read ($params) { - return Comment::markasread($params['comment_id'], $params['user_id']); + Comment::markasread($params['comment_id'], $params['user_id']); } function comment_read_permission ($comment_id) { diff --git a/www/includes/comments.res.php b/www/includes/comments.res.php index 9318272..4886d21 100644 --- a/www/includes/comments.res.php +++ b/www/includes/comments.res.php @@ -1,422 +1,425 @@ - smartyresource_comments_get_thread(): %s', __METHOD__, __LINE__, $board)); - return smartyresource_comments_get_commenttree($id, true); - } else { - //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_thread(): %s', __METHOD__, __LINE__, $board)); - return smartyresource_comments_get_childposts($id, $board); - } -} - -/** - * tpl resource - comments get template - * - * Aufbau comments-resource: - * - ID z.B. comments:12345 - * -> holt comment 12345 - * - * BOARD - ID z.B. comments:b-123 - * -> holt thread 123 aus dem board b - * boards können mit dem einzelnen character (aus table) angegeben werden. - * - * @author [z]biko - * @version 2.1 - * @since 1.0 function added - * @since 2.0 `26.10.2018` `IneX` various optimizations, structured html (schema.org) - * @since 2.1 `22.01.2020` `IneX` Fix sizeof() to only be called when variable is an array, and therefore guarantee it's Countable (eliminating parsing warnings) - * - * @global object $db Globales Class-Object mit allen MySQL-Methoden um unser Template zu laden, und '$tpl_source' zuzuweisen - */ -function smartyresource_comments_get_template ($tpl_name, &$tpl_source, &$smarty) { - global $db; - - $tpl_source = ''; - - $name = explode('-', $tpl_name); - //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_template($name): %s', __METHOD__, __LINE__, $tpl_name)); - if (is_array($name) && sizeof($name) == 1) - { - /** forum - commenttree holen */ - $tpl_source = smartyresource_comments_get_commenttree($name[0]); - //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_commenttree(): %s', __METHOD__, __LINE__, $name[0])); - } else { - /** thread - thread holen */ - //$tpl_source = smartyresource_comments_get_thread(Comment::getParentid($name[1], 3), $name[0]); - $tpl_source = smartyresource_comments_get_thread($name[1], $name[0]); - //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_thread(): %s, %s', __METHOD__, __LINE__, $name[1], $name[0])); - } - - return true; -} - -/** - * tpl resource - comments get navigation - * - * @author [z]biko - * @author IneX - * @version 2.0 - * @since 1.0 `[z]biko` function added - * @since 2.0 `14.01.2019` `IneX` added schema.org tags - * - * @param integer $id Comment-ID - * @param integer $thread_id - * @param string $board - * @global object $db Globales Class-Object mit allen MySQL-Methoden - * @global object $smarty Globales Class-Object mit allen Smarty-Methoden - * @return string - */ -function smartyresource_comments_get_navigation ($id, $thread_id, $board) { - global $db, $smarty; - - $html = ' -
'; - - $count = 1; - $parent_id = $id; - while ($parent_id > $thread_id) { - $up_e = $db->query('SELECT * FROM comments WHERE id='.$parent_id, __FILE__, __LINE__, __FUNCTION__); - $up = $db->fetch($up_e); - - $html .= ''; - $html .= ''; - $html .= ''.$count.' up'; - $html .= ''; - $html .= ' | '; - $html .= ''; - - $parent_id = $up['parent_id']; - $count++; - } - - $html .= Comment::getLinkThread($board, $thread_id); - - $html .= '
'; - - $html .= - '' - .'' - .'' - .'' - .'
' - .'' - .'^^^ Additional posts ^^^' - .'
' - ; - - return $html; - return $smarty->fetch('file:layout/partials/forum/comments_navigation'); -} - -/** - * tpl resource - comments get comment-tree - * - * @author [z]biko - * @author IneX - * @version 3.2 - * @since 1.0 `[z]biko` function added - * @since 2.0 `26.10.2018` `IneX` function code cleanup & optimized, added structured data (schema.org) and google-off/-on, added Thread-Switch - * @since 3.0 `30.10.2018` `IneX` added check of $user->is_loggedin() to Query for Member-specific joins - * @since 3.1 `14.01.2019` `IneX` fixed schema.org tags - * @since 3.2 `22.01.2020` `IneX` Fix sizeof() to only be called when variable is an array, and therefore guarantee it's Countable (eliminating parsing warnings) - * - * @TODO ganzes HTML in ein Smarty TPL auslagern - * - * @see smartyresource_comments_get_navigation(), smartyresource_comments_get_childposts() - * @see Comment::getLinkThread(), Comment::formatPost(), Comment::getNumChildposts() - * @param integer $id Comment-ID - * @param boolean $is_thread Switch to check if get_commenttree is for initial 'f' post (=Thread Comment) or not (any regular Comment) - Default: false - * @global object $db Globales Class-Object mit allen MySQL-Methoden - * @global object $user Globales Class-Object mit den User-Methoden & Variablen - * @global object $smarty Globales Class-Object mit allen Smarty-Methoden - * @return string - */ -function smartyresource_comments_get_commenttree ($id, $is_thread=false) { - global $db, $user, $smarty; - - $sql = 'SELECT - comments.*, - UNIX_TIMESTAMP(comments.date) date, - UNIX_TIMESTAMP(comments.date_edited) date_edited, - user.clan_tag, user.username, - count(c2.id) as numchildposts' - .($user->is_loggedin() ? ', IF(ISNULL(cs.comment_id), 0, 1) AS issubscribed' : ''). - ' FROM comments - LEFT JOIN user ON (comments.user_id = user.id) - LEFT JOIN comments as c2 ON (comments.id = c2.parent_id AND comments.board = c2.board)' - .($user->is_loggedin() ? 'LEFT JOIN comments_subscriptions cs ON (comments.id = cs.id AND comments.board = cs.board AND cs.user_id = '.$user->id.')' : ''). - ' WHERE comments.id = '.$id.' GROUP BY comments.id'; - $rs = $db->fetch($db->query($sql, __FILE__, __LINE__, __FUNCTION__)); - - $html = '{if $comments_top_additional == 1}'; - $html .= smartyresource_comments_get_navigation($rs['id'], $rs['thread_id'], $rs['board']); - $html .= '{else}'; - - $html .= - '' - .''; - - $html .= - '{foreach from=$hdepth item=it key=k}'. - '{if is_array($hdepth) && $k == (sizeof($hdepth) - 1)}'; - if($rs['numchildposts'] > 0) { - $html .= - '' - ; - } else { - $html .= - '{if $it == "space"}'. - ''. - '{else}'. - ''. - '{/if}'; - } - $html .= - '{else}'. - ''. - '{/if}'. - '{/foreach}'; - - $html .= - '
' - .'' - .'' - .'{if $user->id>0 && in_array('.$rs['id'].', $comments_unread)}' - .'{assign var=comment_color value=$color.newcomment}' - .'{comment_mark_read comment_id="'.$rs['id'].'" user_id=$user->id}' - .'{elseif $user->id == '.$rs['user_id'].'}' - .'{assign var=comment_color value=$color.owncomment}' - .'{else}' - .'{assign var=comment_color value=$color.background}' - .'{/if}' - .'{capture assign="sizeof_hdepth"}{sizeof array=$hdepth}{/capture}' - .'' - .'' - .''; - - $html .= ''; - ($is_thread ? $html .= '' : ''); - $html .= '
' - .'
{$smarty.const.SITE_HOSTNAME}
' - .'' - .' by '.$user->userpagelink($rs['user_id'], $rs['clan_tag'], $rs['username']) - .' @ {datename date='.$rs['date'].'}' - ; - - if($rs['date_edited'] > 0) { - $html .= ', edited @ {datename date='.$rs['date_edited'].'}'; - } - - $html .= ''; - $html .= '{if $user->from_mobile} - top -{else} - nach oben -{/if}'; - $html .= '
'; - - /** Subscribe / Unsubscribe */ - $html .= '{if $user->id > 0}' - .'{if in_array('.$rs['id'].', $comments_subscribed)} - [unsubscribe] - {else} - [subscribe] - {/if} - {/if}'; - - /** Edit Comment */ - $html .= '{if $user->id == '.$rs['user_id'].'}' - .'[edit] ' - .'{/if}'; - - /** Reply-to Comment */ - $html .= '{if $user->id > 0}' - .'' - .'' - .'{/if}'; - $html .= ''; - $html .= '
'; - if (!$rs['error']) { - $html .= Comment::formatPost($rs['text']); - } else { - $html .= '{literal}'.$rs['error'].'{/literal}'; - } - $replyCount = Comment::getNumChildposts($rs['board'], $rs['id']); - if ($replyCount > 0) $html .= ' - - - '; - if ($replyCount > 0) $html .= ''; - $html .= '
'; - $html .= '{/if}'; - - if(!is_numeric($rs['id'])) - { - echo sprintf('[ERROR] <%s:%d> $rs[id] is not numeric: "%d"', __FILE__, __LINE__, $rs['id']); - exit; - //$html .= '$rs[id] is not numeric! '.__FILE__.' Line: '.__LINE__; - } - $html .= '{if !$comments_no_childposts}'; - $html .= smartyresource_comments_get_childposts($rs['id'], $rs['board']); - $html .= '{/if}'; - - return $html; -} - -/** - * tpl resource - comments get child-posts - * - * @author [z]biko - * @version 2.2 - * @since 1.0 function added - * @since 2.0 `26.10.2018` `IneX` function code cleanup & optimized - * @since 2.1 `22.01.2020` `IneX` Fix sizeof() to only be called when variable is an array, and therefore guarantee it's Countable (eliminating parsing warnings) - * @since 2.2 `04.12.2020` `IneX` Fix error in compiled template "Warning: count(): Parameter must be an array or an object that implements Countable" - * - * @var $color - * @uses Comment::getNumChildposts() - * @uses smarty_comment_colorfade() - * @param integer $parent_id - * @param string $board - * @global object $db Globales Class-Object mit allen MySQL-Methoden - * @global object $user Globales Class-Object mit den User-Methoden & Variablen - * @global object $smarty Globales Class-Object mit allen Smarty-Methoden - * @return string - */ -function smartyresource_comments_get_childposts ($parent_id, $board) { - global $db, $user, $smarty; - - /** Validate passed parameters */ - if(empty($parent_id) || !is_numeric($parent_id) || is_array($parent_id) || $parent_id < 0) { - user_error(sprintf('<%s:%d> $parent_id is not numeric: %s', __FILE__, __LINE__, $parent_id), E_USER_WARNING); - exit; - } - if (empty($board) || is_numeric($board) || is_array($board)) { - user_error(sprintf('<%s:%d> $board is not valid: %s', __FILE__, __LINE__, $board), E_USER_WARNING); - exit; - } - - $html = '{if not $hdepth}{assign_array var=counthdepth value=0}{else}{assign var=counthdepth value=$hdepth|@count}{/if}'; // TODO Smarty 3.x can assign default value (and drop @): $var|default:array()|count - $html .= '{if ($user->id != 0 && $counthdepth <= $user->maxdepth) || ($user->id == 0 && $counthdepth < $comments_default_maxdepth) || '.Comment::getNumChildposts($board, $parent_id).' == 0}'; - - $html .= '
'; - - $sql = 'SELECT comments.* FROM comments WHERE comments.parent_id='.$parent_id.' AND comments.board="'.$board.'" ORDER BY comments.id'; - $result = $db->query($sql, __FILE__, __LINE__, __FUNCTION__); - $rcount = 0; - while($child = $db->fetch($result)) { - $depth2 = $depth; - $rcount++; - $html .= '{comment_extend_depth depth=$hdepth childposts='.Comment::getNumChildposts($board, $parent_id).' rcount='.$rcount.'}'; - $html .= '{include file="comments:'.$child['id'].'" comments_top_additional=0}'; - $html .= '{comment_remove_depth depth=$hdepth}'; - } - $html .= '
'; - - $html .= '{else}'; - - $html .= '{comment_extend_depth depth=$hdepth childposts='.Comment::getNumChildposts($board, $parent_id).' rcount='.$rcount.'}'; - - $html .= - '' - .''; - - $html .= - '{foreach from=$hdepth item=it}'. - ''. - '{/foreach}'; - - // restlicher output - $html .= - '' // Manually added 1 space to fix alignment of "Additional posts" - .'' - .'
' - .'' - .'' - - .'' - .'' - .'
' - .'' - .' Additional posts' - .' {if $user->id!=0}(du hast Forumanzeigeschwelle {$user->maxdepth} eingestellt){/if}' - .'
' - - .'
' - ; - - $html .= '{comment_remove_depth depth=$hdepth}'; - - $html .= '{/if}'; - - return $html; -} + smartyresource_comments_get_thread(): %s', __METHOD__, __LINE__, $board)); + return smartyresource_comments_get_commenttree($id, true); + } else { + //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_thread(): %s', __METHOD__, __LINE__, $board)); + return smartyresource_comments_get_childposts($id, $board); + } +} + +/** + * tpl resource - comments get template + * + * Aufbau comments-resource: + * - ID z.B. comments:12345 + * -> holt comment 12345 + * + * BOARD - ID z.B. comments:b-123 + * -> holt thread 123 aus dem board b + * boards können mit dem einzelnen character (aus table) angegeben werden. + * + * @author [z]biko + * @version 2.1 + * @since 1.0 function added + * @since 2.0 `26.10.2018` `IneX` various optimizations, structured html (schema.org) + * @since 2.1 `22.01.2020` `IneX` Fix sizeof() to only be called when variable is an array, and therefore guarantee it's Countable (eliminating parsing warnings) + * + * @global object $db Globales Class-Object mit allen MySQL-Methoden um unser Template zu laden, und '$tpl_source' zuzuweisen + */ +function smartyresource_comments_get_template ($tpl_name, &$tpl_source, &$smarty) { + global $db; + + $tpl_source = ''; + + $name = explode('-', $tpl_name); + //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_template($name): %s', __METHOD__, __LINE__, $tpl_name)); + if (is_array($name) && sizeof($name) == 1) + { + /** forum - commenttree holen */ + $tpl_source = smartyresource_comments_get_commenttree($name[0]); + //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_commenttree(): %s', __METHOD__, __LINE__, $name[0])); + } else { + /** thread - thread holen */ + //$tpl_source = smartyresource_comments_get_thread(Comment::getParentid($name[1], 3), $name[0]); + $tpl_source = smartyresource_comments_get_thread($name[1], $name[0]); + //if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> smartyresource_comments_get_thread(): %s, %s', __METHOD__, __LINE__, $name[1], $name[0])); + } + + return true; +} + +/** + * tpl resource - comments get navigation + * + * @author [z]biko + * @author IneX + * @version 2.0 + * @since 1.0 `[z]biko` function added + * @since 2.0 `14.01.2019` `IneX` added schema.org tags + * + * @param integer $id Comment-ID + * @param integer $thread_id + * @param string $board + * @global object $db Globales Class-Object mit allen MySQL-Methoden + * @global object $smarty Globales Class-Object mit allen Smarty-Methoden + * @return string + */ +function smartyresource_comments_get_navigation ($id, $thread_id, $board) { + global $db, $smarty; + + $html = ' +
'; + + $count = 1; + $parent_id = $id; + while ($parent_id > $thread_id) { + $up_e = $db->query('SELECT * FROM comments WHERE id=?', __FILE__, __LINE__, __FUNCTION__, [$parent_id]); + $up = $db->fetch($up_e); + + $html .= ''; + $html .= ''; + $html .= ''.$count.' up'; + $html .= ''; + $html .= ' | '; + $html .= ''; + + $parent_id = $up['parent_id']; + $count++; + } + + $html .= Comment::getLinkThread($board, $thread_id); + + $html .= '
'; + + $html .= + '' + .'' + .'' + .'' + .'
' + .'' + .'^^^ Additional posts ^^^' + .'
' + ; + + return $html; + return $smarty->fetch('file:layout/partials/forum/comments_navigation'); +} + +/** + * tpl resource - comments get comment-tree + * + * @author [z]biko + * @author IneX + * @version 3.2 + * @since 1.0 `[z]biko` function added + * @since 2.0 `26.10.2018` `IneX` function code cleanup & optimized, added structured data (schema.org) and google-off/-on, added Thread-Switch + * @since 3.0 `30.10.2018` `IneX` added check of $user->is_loggedin() to Query for Member-specific joins + * @since 3.1 `14.01.2019` `IneX` fixed schema.org tags + * @since 3.2 `22.01.2020` `IneX` Fix sizeof() to only be called when variable is an array, and therefore guarantee it's Countable (eliminating parsing warnings) + * + * @TODO ganzes HTML in ein Smarty TPL auslagern + * + * @see smartyresource_comments_get_navigation(), smartyresource_comments_get_childposts() + * @see Comment::getLinkThread(), Comment::formatPost(), Comment::getNumChildposts() + * @param integer $id Comment-ID + * @param boolean $is_thread Switch to check if get_commenttree is for initial 'f' post (=Thread Comment) or not (any regular Comment) - Default: false + * @global object $db Globales Class-Object mit allen MySQL-Methoden + * @global object $user Globales Class-Object mit den User-Methoden & Variablen + * @global object $smarty Globales Class-Object mit allen Smarty-Methoden + * @return string + */ +function smartyresource_comments_get_commenttree ($id, $is_thread=false) { + global $db, $user, $smarty; + + $params = []; + $sql = 'SELECT + comments.*, + UNIX_TIMESTAMP(comments.date) date, + UNIX_TIMESTAMP(comments.date_edited) date_edited, + user.clan_tag, user.username, + count(c2.id) as numchildposts' + .($user->is_loggedin() ? ', IF(ISNULL(cs.comment_id), 0, 1) AS issubscribed' : '').' + FROM comments + LEFT JOIN user ON (comments.user_id = user.id) + LEFT JOIN comments as c2 ON (comments.id = c2.parent_id AND comments.board = c2.board)' + .($user->is_loggedin() ? 'LEFT JOIN comments_subscriptions cs ON (comments.id = cs.id AND comments.board = cs.board AND cs.user_id=?)' : '').' + WHERE comments.id=? GROUP BY comments.id'; + if ($user->is_loggedin()) $params[] = $user->id; + $params[] = $id; + $rs = $db->fetch($db->query($sql, __FILE__, __LINE__, __FUNCTION__, $params)); + + $html = '{if $comments_top_additional == 1}'; + $html .= smartyresource_comments_get_navigation($rs['id'], $rs['thread_id'], $rs['board']); + $html .= '{else}'; + + $html .= + '' + .''; + + $html .= + '{foreach from=$hdepth item=it key=k}'. + '{if is_array($hdepth) && $k == (sizeof($hdepth) - 1)}'; + if($rs['numchildposts'] > 0) { + $html .= + '' + ; + } else { + $html .= + '{if $it == "space"}'. + ''. + '{else}'. + ''. + '{/if}'; + } + $html .= + '{else}'. + ''. + '{/if}'. + '{/foreach}'; + + $html .= + '
' + .'' + .'' + .'{if $user->id>0 && in_array('.$rs['id'].', $comments_unread)}' + .'{assign var=comment_color value=$color.newcomment}' + .'{comment_mark_read comment_id="'.$rs['id'].'" user_id=$user->id}' + .'{elseif $user->id == '.$rs['user_id'].'}' + .'{assign var=comment_color value=$color.owncomment}' + .'{else}' + .'{assign var=comment_color value=$color.background}' + .'{/if}' + .'{capture assign="sizeof_hdepth"}{sizeof array=$hdepth}{/capture}' + .'' + .'' + .''; + + $html .= ''; + ($is_thread ? $html .= '' : ''); + $html .= '
' + .'
{$smarty.const.SITE_HOSTNAME}
' + .'' + .' by '.$user->userpagelink($rs['user_id'], $rs['clan_tag'], $rs['username']) + .' @ {datename date='.$rs['date'].'}' + ; + + if($rs['date_edited'] > 0) { + $html .= ', edited @ {datename date='.$rs['date_edited'].'}'; + } + + $html .= ''; + $html .= '{if $user->from_mobile} - top -{else} - nach oben -{/if}'; + $html .= '
'; + + /** Subscribe / Unsubscribe */ + $html .= '{if $user->id > 0}' + .'{if in_array('.$rs['id'].', $comments_subscribed)} + [unsubscribe] + {else} + [subscribe] + {/if} + {/if}'; + + /** Edit Comment */ + $html .= '{if $user->id == '.$rs['user_id'].'}' + .'[edit] ' + .'{/if}'; + + /** Reply-to Comment */ + $html .= '{if $user->id > 0}' + .'' + .'' + .'{/if}'; + $html .= ''; + $html .= '
'; + if (!$rs['error']) { + $html .= Comment::formatPost($rs['text']); + } else { + $html .= '{literal}'.$rs['error'].'{/literal}'; + } + $replyCount = Comment::getNumChildposts($rs['board'], $rs['id']); + if ($replyCount > 0) $html .= ' + + + '; + if ($replyCount > 0) $html .= ''; + $html .= '
'; + $html .= '{/if}'; + + if(!is_numeric($rs['id'])) + { + echo sprintf('[ERROR] <%s:%d> $rs[id] is not numeric: "%d"', __FILE__, __LINE__, $rs['id']); + exit; + //$html .= '$rs[id] is not numeric! '.__FILE__.' Line: '.__LINE__; + } + $html .= '{if !$comments_no_childposts}'; + $html .= smartyresource_comments_get_childposts($rs['id'], $rs['board']); + $html .= '{/if}'; + + return $html; +} + +/** + * tpl resource - comments get child-posts + * + * @author [z]biko + * @version 2.2 + * @since 1.0 function added + * @since 2.0 `26.10.2018` `IneX` function code cleanup & optimized + * @since 2.1 `22.01.2020` `IneX` Fix sizeof() to only be called when variable is an array, and therefore guarantee it's Countable (eliminating parsing warnings) + * @since 2.2 `04.12.2020` `IneX` Fix error in compiled template "Warning: count(): Parameter must be an array or an object that implements Countable" + * + * @var $color + * @uses Comment::getNumChildposts() + * @uses smarty_comment_colorfade() + * @param integer $parent_id + * @param string $board + * @global object $db Globales Class-Object mit allen MySQL-Methoden + * @global object $user Globales Class-Object mit den User-Methoden & Variablen + * @global object $smarty Globales Class-Object mit allen Smarty-Methoden + * @return string + */ +function smartyresource_comments_get_childposts ($parent_id, $board) { + global $db; + + /** Validate passed parameters */ + if(empty($parent_id) || !is_numeric($parent_id) || is_array($parent_id) || $parent_id < 0) { + user_error(sprintf('<%s:%d> $parent_id is not numeric: %s', __FILE__, __LINE__, $parent_id), E_USER_WARNING); + exit; + } + if (empty($board) || is_numeric($board) || is_array($board)) { + user_error(sprintf('<%s:%d> $board is not valid: %s', __FILE__, __LINE__, $board), E_USER_WARNING); + exit; + } + + $html = '{if not $hdepth}{assign_array var=counthdepth value=0}{else}{assign var=counthdepth value=$hdepth|@count}{/if}'; // TODO Smarty 3.x can assign default value (and drop @): $var|default:array()|count + $html .= '{if ($user->id != 0 && $counthdepth <= $user->maxdepth) || ($user->id == 0 && $counthdepth < $comments_default_maxdepth) || '.Comment::getNumChildposts($board, $parent_id).' == 0}'; + + $html .= '
'; + + $sql = 'SELECT comments.* FROM comments WHERE comments.parent_id=? AND comments.board=? ORDER BY comments.id'; + $result = $db->query($sql, __FILE__, __LINE__, __FUNCTION__, [$parent_id, $board]); + $rcount = 0; + while($child = $db->fetch($result)) { + //$depth2 = $depth; + $rcount++; + $html .= '{comment_extend_depth depth=$hdepth childposts='.Comment::getNumChildposts($board, $parent_id).' rcount='.$rcount.'}'; + $html .= '{include file="comments:'.$child['id'].'" comments_top_additional=0}'; + $html .= '{comment_remove_depth depth=$hdepth}'; + } + $html .= '
'; + + $html .= '{else}'; + + $html .= '{comment_extend_depth depth=$hdepth childposts='.Comment::getNumChildposts($board, $parent_id).' rcount='.$rcount.'}'; + + $html .= + '' + .''; + + $html .= + '{foreach from=$hdepth item=it}'. + ''. + '{/foreach}'; + + // restlicher output + $html .= + '' // Manually added 1 space to fix alignment of "Additional posts" + .'' + .'
' + .'' + .'' + + .'' + .'' + .'
' + .'' + .' Additional posts' + .' {if $user->id!=0}(du hast Forumanzeigeschwelle {$user->maxdepth} eingestellt){/if}' + .'
' + + .'
' + ; + + $html .= '{comment_remove_depth depth=$hdepth}'; + + $html .= '{/if}'; + + return $html; +} diff --git a/www/includes/config.inc.php b/www/includes/config.inc.php index 781a5d3..f2b075d 100644 --- a/www/includes/config.inc.php +++ b/www/includes/config.inc.php @@ -251,8 +251,12 @@ * @const SMARTY_404PAGE_TPL 404 "Page not found" Smarty-Template reference */ if (!defined('SMARTY_DIR')) define('SMARTY_DIR', (isset($_ENV['SMARTY_DIR']) ? $_ENV['SMARTY_DIR'] : null)); -if (!defined('SMARTY_TRUSTED_DIRS')) define('SMARTY_TRUSTED_DIRS', (isset($_ENV['SMARTY_TRUSTED_DIRS']) ? (array)$_ENV['SMARTY_TRUSTED_DIRS'] : null)); -if (!defined('SMARTY_TEMPLATES_HTML')) define('SMARTY_TEMPLATES_HTML', (isset($_ENV['SMARTY_TEMPLATES_HTML']) ? (array)$_ENV['SMARTY_TEMPLATES_HTML'] : null)); +if (!defined('SMARTY_TRUSTED_DIRS')) { + define('SMARTY_TRUSTED_DIRS', isset($_ENV['SMARTY_TRUSTED_DIRS']) ? explode(',', $_ENV['SMARTY_TRUSTED_DIRS']) : []); +} +if (!defined('SMARTY_TEMPLATES_HTML')) { + define('SMARTY_TEMPLATES_HTML', isset($_ENV['SMARTY_TEMPLATES_HTML']) ? explode(',', $_ENV['SMARTY_TEMPLATES_HTML']) : []); +} if (!defined('SMARTY_CACHE')) define('SMARTY_CACHE', (isset($_ENV['SMARTY_CACHE']) ? $_ENV['SMARTY_CACHE'] : null)); if (!defined('SMARTY_COMPILE')) define('SMARTY_COMPILE', (isset($_ENV['SMARTY_COMPILE']) ? $_ENV['SMARTY_COMPILE'] : null)); if (!defined('SMARTY_PACKAGES_DIR')) define('SMARTY_PACKAGES_DIR', (isset($_ENV['SMARTY_PACKAGES_DIR']) ? $_ENV['SMARTY_PACKAGES_DIR'] : null)); @@ -264,11 +268,13 @@ * Define various Gallery related constants. * @const MAX_PIC_SIZE The maximum width & height for pictures * @const MAX_THUMBNAIL_SIZE The maximum width & height for pic thumbnails - * @const THUMBPAGE The image size for Thumbnail pictures */ -if (!defined('MAX_PIC_SIZE')) define('MAX_PIC_SIZE', (isset($_ENV['GALLERY_MAX_PIC_SIZE']) ? (array)$_ENV['GALLERY_MAX_PIC_SIZE'] : null)); -if (!defined('MAX_THUMBNAIL_SIZE')) define('MAX_THUMBNAIL_SIZE', (isset($_ENV['GALLERY_MAX_THUMBNAIL_SIZE']) ? (array)$_ENV['GALLERY_MAX_THUMBNAIL_SIZE'] : null)); -if (!defined('THUMBPAGE')) define('THUMBPAGE', (isset($_ENV['GALLERY_THUMBPAGE']) ? (array)$_ENV['GALLERY_THUMBPAGE'] : null)); +if (!defined('MAX_PIC_SIZE')) { + define('MAX_PIC_SIZE', (isset($_ENV['GALLERY_MAX_PIC_WIDTH']) && isset($_ENV['GALLERY_MAX_PIC_HEIGHT']) ? ['width' => $_ENV['GALLERY_MAX_PIC_WIDTH'], 'height' => $_ENV['GALLERY_MAX_PIC_HEIGHT']] : ['width' => 800, 'height' => 600])); +} +if (!defined('MAX_THUMBNAIL_SIZE')) { + define('MAX_THUMBNAIL_SIZE', (isset($_ENV['GALLERY_MAX_THUMB_WIDTH']) && isset($_ENV['GALLERY_MAX_THUMB_HEIGHT']) ? ['width' => $_ENV['GALLERY_MAX_THUMB_WIDTH'], 'height' => $_ENV['GALLERY_MAX_THUMB_HEIGHT']] : ['width' => 150, 'height' => 150])); +} /** * Define various NASA API and APOD related constants. @@ -330,7 +336,7 @@ if (!defined('ZORG_VEREIN_KONTO_SWIFT')) define('ZORG_VEREIN_KONTO_SWIFT', (isset($_ENV['ZORG_VEREIN_KONTO_SWIFT']) ? $_ENV['ZORG_VEREIN_KONTO_SWIFT'] : null)); if (!defined('ZORG_VEREIN_KONTO_IBAN')) define('ZORG_VEREIN_KONTO_IBAN', (isset($_ENV['ZORG_VEREIN_KONTO_IBAN']) ? $_ENV['ZORG_VEREIN_KONTO_IBAN'] : null)); if (!defined('ZORG_VEREIN_KONTO_IBAN_QRBILL')) define('ZORG_VEREIN_KONTO_IBAN_QRBILL', (isset($_ENV['ZORG_VEREIN_KONTO_IBAN_QRBILL']) ? $_ENV['ZORG_VEREIN_KONTO_IBAN_QRBILL'] : null)); -if (!defined('ZORG_VEREIN_KONTO_CURRENCY')) define('ZORG_VEREIN_KONTO_CURRENCY', (isset($_ENV['ZORG_VEREIN_KONTO_CURRENCY']) ? $_ENV['ZORG_VEREIN_KONTO_CURRENCY'] : null)); +if (!defined('ZORG_VEREIN_KONTO_CURRENCY')) define('ZORG_VEREIN_KONTO_CURRENCY', (isset($_ENV['ZORG_VEREIN_KONTO_CURRENCY']) ? $_ENV['ZORG_VEREIN_KONTO_CURRENCY'] : 'CHF')); if (!defined('ZORG_VEREIN_KONTO_BESRID')) define('ZORG_VEREIN_KONTO_BESRID', (isset($_ENV['ZORG_VEREIN_KONTO_BESRID']) ? $_ENV['ZORG_VEREIN_KONTO_BESRID'] : null)); /** @@ -341,23 +347,28 @@ * @const ERRORLOG_FILETYPE sets the file extension used for the error log file * @const ERRORLOG_DIR sets the directory for logging the custom user_errors * @const ERRORLOG_FILEPATH sets the directory & file path for logging the custom user_errors to - * @include errlog.inc.php Errorlogging Class: Load the zorg Error Handling + * @const ERRORLOG_LEVELS sets the verbosity of logging errors, warnings, and notices caused by the application + * @const ERRORLOG_DEBUG_SCOPE (Optional) sets a focused scope for DEBUG log entries + * @include errlog.inc.php Errorlogging Class: Load the zorg Error and Debug Handling */ if (!defined('ERRORLOG_FILETYPE')) define('ERRORLOG_FILETYPE', (isset($_ENV['ERRORLOG_FILETYPE']) ? $_ENV['ERRORLOG_FILETYPE'] : '.log')); if (!defined('ERRORLOG_DIR')) define('ERRORLOG_DIR', (isset($_ENV['ERRORLOG_DIR']) ? $_ENV['ERRORLOG_DIR'] : null)); if (!defined('ERRORLOG_FILE')) define('ERRORLOG_FILE', ERRORLOG_DIR.date('Y-m-d').ERRORLOG_FILETYPE); +if (!defined('ERRORLOG_LEVELS')) define('ERRORLOG_LEVELS', (isset($_ENV['ERROR_REPORTING_LEVELS']) ? $_ENV['ERROR_REPORTING_LEVELS'] : null)); +if (!defined('ERRORLOG_DEBUG_SCOPE')) define('ERRORLOG_DEBUG_SCOPE', (isset($_ENV['DEBUG_SCOPE']) ? $_ENV['DEBUG_SCOPE'] : null)); require_once INCLUDES_DIR.'errlog.inc.php'; //set_error_handler('zorgErrorHandler'); -error_reporting($_ENV['ERROR_REPORTING_LEVELS']); /** * Include some generic files and functions to make them globally available by default. * (keep this at the end of the config.inc.php!) * * @include strings.inc.php Various Placeholder-Strings related constants and files. + * @include util.inc.php Various Helper Functions and Code Utilities. * @include notifications.inc.php Various Notification System-related constants and files * @include telegrambot.inc.php Required to send Telegram-Notifications */ include_once INCLUDES_DIR.'strings.inc.php'; +include_once INCLUDES_DIR.'util.inc.php'; include_once INCLUDES_DIR.'notifications.inc.php'; include_once INCLUDES_DIR.'telegrambot.inc.php'; diff --git a/www/includes/errlog.inc.php b/www/includes/errlog.inc.php index a91bde8..0984a1e 100644 --- a/www/includes/errlog.inc.php +++ b/www/includes/errlog.inc.php @@ -8,18 +8,19 @@ 'error' => true, 'warning' => true, 'unknown' => false), // schaltet das wenn möglich nicht ein - z.b. auf der startseite gibt das alle 6500 (!) errors aus - 'errlog' => array( - 'fatal' => true, - 'error' => true, - 'warning' => true, - 'unknown' => false) // schaltet das wenn möglich nicht ein - z.b. auf der startseite speichert das alle 6500 (!) errors im file (das gibt ca. 1MB) - ); -} + 'errlog' => array( + 'fatal' => true, + 'error' => true, + 'warning' => true, + 'unknown' => false) // schaltet das wenn möglich nicht ein - z.b. auf der startseite speichert das alle 6500 (!) errors im file (das gibt ca. 1MB) + ); + } if (!defined('FATAL')) define('FATAL', E_USER_ERROR); if (!defined('ERROR')) define('ERROR', E_USER_WARNING); if (!defined('WARNING')) define('WARNING', E_USER_NOTICE); +error_reporting(ERRORLOG_LEVELS); //error_reporting(FATAL | ERROR | WARNING); //set_error_handler('zorgErrorHandler'); @@ -61,3 +62,158 @@ function zorgErrorHandler ($errno, $errstr, $errfile, $errline) if ($errno == FATAL) exit(1); } + +/** + * zorg Code Debugger & Error Logger + * + * Helps debugging when developing locally & verbosing to the error_log(). + * I am annoyed by constant messages spamming the Logoutput, so + * this should help to focus better on parts of the code that + * currently are being worked on (and not distract with tons of + * other messages in the log). + * + * @example zorgDebugger::me()->debug('Required SQL-Query update: <%s> in %s:%d', [$funktion, $file, $line], 'DEPRECATED'); + * @example zorgDebugger::me()->error('The provided ID "%d" is invalid!', [$tplID]); + * + * @version 1.0 + * @since 1.0 `26.12.2024` `IneX` Class added + */ +class zorgDebugger +{ + /** + * @var bool Indicates if the current environment is a development environment. + */ + private static $instance = null; + private $isDevelopmentEnvironment; + + /** + * Constructor for Errorlog. + * Initializes the class and sets the development environment status. + * @uses DEVELOPMENT + */ + public function __construct() + { + $this->isDevelopmentEnvironment = defined('DEVELOPMENT') && DEVELOPMENT; + } + + /** + * Gets a Singleton instance of the zorgDebugger class. + * + * This allows to call zorgDebugger::me()->... WITHOUT instantiating the Class manually, + * and WITHOUT including it or using something like "global $errlog;". + * + * @return zorgDebugger The singleton instance of the Errorlog class. + */ + public static function me(): zorgDebugger + { + if (self::$instance === null) { + self::$instance = new zorgDebugger(); + } + + return self::$instance; + } + + /** + * Logs a debug message. + * Only log debug if in a development environment; + * and only if either no debug scope was defined - or the debug scope matches the origin. + * + * @param string $message The message format string. + * @param array $params The parameters to be inserted into the message format string. + * @param string $customLoglevel Overwrite the [DEBUG] loglevel using a custom value. E.g. DEPRECATED + */ + public function debug($message, $params = [], $customLoglevel='DEBUG') + { + /** Determines if a message should be logged based on the origin. */ + if ($this->isDevelopmentEnvironment) { + $origin = $this->getOrigin(); + + if (is_null(ERRORLOG_DEBUG_SCOPE) || + ERRORLOG_DEBUG_SCOPE === $origin['function'] || + ERRORLOG_DEBUG_SCOPE === basename($origin['file'])) + { + $this->log($customLoglevel, $message, $params, $origin); + } + } + } + + /** + * Logs an info message. + * + * @param string $message The message format string. + * @param array $params The parameters to be inserted into the message format string. + */ + public function info($message, $params = []) + { + $this->log('INFO', $message, $params, $this->getOrigin()); + } + + /** + * Logs an error message. + * + * @param string $message The message format string. + * @param array $params The parameters to be inserted into the message format string. + */ + public function error($message, $params = []) + { + $this->log('ERROR', $message, $params, $this->getOrigin()); + } + + /** + * Logs a warning message. + * + * @param string $message The message format string. + * @param array $params The parameters to be inserted into the message format string. + */ + public function warn($message, $params = []) + { + $this->log('WARNING', $message, $params, $this->getOrigin()); + } + + /** + * Handles the logging of a message. + * Example: [LOGLEVEL] PARSED-MESSAGE + * + * @param string $level The log level (e.g. DEBUG, INFO, ERROR). + * @param string $message The message format string. + * @param array $params The parameters to be inserted into the message format string. + * @param array $origina (Optional) Origin details from where a log message was triggered from. + */ + private function log($level, $message, $params, $origin = []) + { + $logOrigin = (!empty($origin['function']) ? $origin['function'] : (!empty($origin['file']) ? $origin['file'] : '')); + $logLine = (!empty($origin['line']) ? ':'.$origin['line'] : ''); + $formattedMessage = vsprintf($message, $params); + $logMessage = sprintf('[%s] <%s%s> %s', $level, $logOrigin, $logLine, $formattedMessage); + error_log($logMessage); + } + + /** + * Retrieves the origin details of the log message. + * + * @return array The origin details including file, function, and line. + */ + private function getOrigin() + { + $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); + + $origin = [ + 'function' => '', + 'file' => '', + 'line' => 0 + ]; + + if (isset($backtrace[2])) { + if (isset($backtrace[2]['function'])) { + $origin['function'] = $backtrace[2]['function']; + } + if (isset($backtrace[2]['file'])) { + $origin['file'] = basename($backtrace[2]['file']); + } + if (isset($backtrace[2]['line'])) { + $origin['line'] = $backtrace[2]['line']; + } + } + return $origin; + } +} diff --git a/www/includes/forum.inc.php b/www/includes/forum.inc.php index 2f9aab7..7bd2341 100644 --- a/www/includes/forum.inc.php +++ b/www/includes/forum.inc.php @@ -150,7 +150,7 @@ static function compile_template($thread_id, $comment_id, $board='f') } else { $errortext = ''; foreach ($error as $value) $errortext .= $value.'
'; - $comments_update_query = $db->update('comments', ['id', $comment_id], ['error' => escape_text($errortext)], __FILE__, __LINE__, __METHOD__); + $comments_update_query = $db->update('comments', ['id', $comment_id], ['error' => $errortext], __FILE__, __LINE__, __METHOD__); $smarty->compile($resource, $error); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> $smarty->compile ERROR', __METHOD__, __LINE__)); return false; @@ -235,8 +235,8 @@ static function getNumChildposts($board, $comment_id) { /** Parent zu $comment_id is NOT cached yet... */ if (!isset($_cache["$board $comment_id"])) { - $sql = 'SELECT * FROM comments where parent_id = '.$comment_id.' AND board="'.$board.'"'; - $_cache["$board $comment_id"] = $db->num($db->query($sql, __FILE__, __LINE__, __METHOD__)); + $sql = 'SELECT * FROM comments where parent_id=? AND board=?'; + $_cache["$board $comment_id"] = $db->num($db->query($sql, __FILE__, __LINE__, __METHOD__, [$comment_id, $board])); } return $_cache["$board $comment_id"]; } else { @@ -471,12 +471,13 @@ static function getLinkThread($board, $thread_id, $output_html=true) { static function getChildPostsFormFields($id, $parent_id, $comment_id=0, $depth=0) { global $db; - if($depth < 7) { + $html = ''; + if($depth < 7) + { if($comment_id == 0) $comment_id = $parent_id; - - $sql = "select * from comments where parent_id =".$comment_id; - $result = $db->query($sql, __FILE__, __LINE__, __METHOD__); + $sql = 'SELECT * FROM comments WHERE parent_id = ?'; + $result = $db->query($sql, __FILE__, __LINE__, __METHOD__, [$comment_id]); while ($rs = $db->fetch($result)) { if($rs['id'] != $id) { @@ -491,9 +492,8 @@ static function getChildPostsFormFields($id, $parent_id, $comment_id=0, $depth=0 $html .= self::getChildPostsFormFields($id, $parent_id, $rs['id'], ($depth+1)); } - - return $html; } + return $html; } /** @@ -501,14 +501,14 @@ static function getChildPostsFormFields($id, $parent_id, $comment_id=0, $depth=0 * * WICHTIG! UNBEDINGT SO LASSEN! * - * @return int + * @param string $board * @param int $id - * @param int $hiers + * @return int */ static function getThreadid($board, $id) { global $db; - $sql = 'SELECT thread_id FROM comments WHERE board="'.$board.'" AND id='.$id; - $rs = $db->fetch($db->query($sql, __FILE__, __LINE__)); + $sql = 'SELECT thread_id FROM comments WHERE board=? AND id=?'; + $rs = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$board, $id])); return $rs['thread_id']; } @@ -557,23 +557,12 @@ static function getSummary($text, $length=20) { } /** - * Mark Comment as 'read' - */ - static function markasread($comment_id, $user_id) { - global $db, $user; - if(defined('USER_USER') && $user->typ >= USER_USER) { - $sql = 'DELETE from comments_unread WHERE user_id = '.$user_id.' AND comment_id='.$comment_id; - $db->query($sql, __FILE__, __LINE__, __METHOD__); - } - } - - /** - * Prüft ob der Comment ein Thread ist - * + * Prüft ob der Comment ein Thread ist. * Prüft, ob der Comment im therads-table eingetragen ist (= thread start) * * @author IneX - * @date 16.03.2008 + * @version 1.0 + * @since 1.0 `16.03.2008` Method added * @param string $board * @param int $id int * @return boolean @@ -586,59 +575,85 @@ static function isThread($board, $id) { return $rs; } - // Mark as unread for all users. - static function markasunread($comment_id) { + /** + * Mark Comment as 'READ'. + * @author [z]biko + * @version 1.1 + * @since 1.0 Method addded + * @since 1.1 `03.12.2023` `IneX` Support with MySQL prepared statements + * + * @param int $commentid + * @param int $user_id + * @return boolean + */ + static function markasread($comment_id, $user_id) + { + global $db, $user; + if((is_numeric($comment_id) && $comment_id>0) && defined('USER_USER') && $user->typ >= USER_USER) + { + $sql = 'DELETE from comments_unread WHERE user_id=? AND comment_id=?'; + $db->query($sql, __FILE__, __LINE__, __METHOD__, [$user_id, $comment_id]); + return true; + } else { + return false; + } + } + + /** + * Mark Comment as 'UNREAD' for all users. + * @author [z]biko + * @version 1.1 + * @since 1.0 Method addded + * @since 1.1 `03.12.2023` `IneX` Unread comments where broken: added support for MySQL prepared statements + * + * @param int $commentid + * @return boolean + */ + static function markasunread($comment_id) + { global $db; - $sql = - " - SELECT - c.thread_id, - c.board, - ct.rights - FROM comments c - LEFT JOIN comments_threads ct - ON (ct.board = c.board AND ct.thread_id = c.thread_id) - WHERE c.id = ".$comment_id." - LIMIT 0, 1 - " - ; - $rs = $db->fetch($db->query($sql, __FILE__, __LINE__)); + /** Validate passed Parameters */ + if (!is_numeric($comment_id) || $comment_id <= 0) return false; + + $sql = 'SELECT c.thread_id, c.board, ct.rights + FROM comments c LEFT JOIN comments_threads ct + ON (ct.board=c.board AND ct.thread_id=c.thread_id) + WHERE c.id=? LIMIT 1'; + $rs = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$comment_id])); - if($rs['rights'] == '') $rs['rights'] = 0; - - - if($rs['rights'] < USER_SPECIAL) { - $sql = "REPLACE INTO comments_unread (user_id, comment_id) - SELECT id, ".$comment_id." - FROM user - WHERE user.usertype >= ? - AND (UNIX_TIMESTAMP(lastlogin)+".USER_OLD_AFTER.") > UNIX_TIMESTAMP(NOW()) - AND forum_boards_unread LIKE CONCAT('%', ?, '%')" - /*AND ISNULL( - SELECT tignore.thread_id, tignore.user_id - FROM comments_threads_ignore tignore - WHERE tignore.thread_id = ".$rs['thread_id']." - AND tignore.user_id = user.id + $userights = (!isset($rs['rights']) || empty($rs['rights']) ? 0 : $rs['rights']); + $board = $rs['board']; + $thread = $rs['thread_id']; + + /** Insert only Unread Commments to Users who are NOT USER_SPECIAL */ + if($userights < USER_SPECIAL) + { + $sql = 'REPLACE INTO comments_unread (user_id, comment_id) + SELECT id, ? FROM user + WHERE user.usertype>=? + AND (UNIX_TIMESTAMP(lastlogin)+?) > UNIX_TIMESTAMP(?) + AND forum_boards_unread LIKE CONCAT("%", ?, "%")' + /*AND ISNULL( + SELECT tignore.thread_id, tignore.user_id + FROM comments_threads_ignore tignore + WHERE tignore.thread_id=$thread + AND tignore.user_id = user.id )*/ ; - $data = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$rs['rights'], $rs['board']])); + $affectedRows = $db->query($sql, __FILE__, __LINE__, __METHOD__, [$comment_id, $userights, USER_OLD_AFTER, timestamp(true), $board]); } else { - $sql = - " - REPLACE INTO comments_unread (user_id, comment_id) - SELECT - user_id - , ".$comment_id." - FROM comments_threads_rights - WHERE board = '".$rs['board']."' - AND thread_id = ".$rs['thread_id']." - " - ; - $data = $db->fetch($db->query($sql, __FILE__, __LINE__)); + $sql = 'REPLACE INTO comments_unread (user_id, comment_id) + SELECT user_id, ? FROM comments_threads_rights + WHERE board=? AND thread_id=?'; + $affectedRows = $db->query($sql, __FILE__, __LINE__, __METHOD__, [$comment_id, $board, $thread]); } + return ($affectedRows > 0 ? true : false); } + /** + * In Forum-Search, highlight the searched keyword(s) with a color + */ static function highliteKeyword($keyword,$text) { global $tborderc; //$keyword = htmlentities($keyword); @@ -667,7 +682,7 @@ static function post($parent_id, $board, $user_id, $text, $msg_users=NULL) /** Parent-Id = 1 wenn man ein ForumThread postet */ $parent_id = ($parent_id <= 0 ? 1 : $parent_id); - if($parent_id <= 0 || !is_numeric($parent_id)) user_error(t('invalid-parent_id', 'commenting'), E_USER_ERROR); + if(!is_numeric($parent_id) || $parent_id <= 0) user_error(t('invalid-parent_id', 'commenting'), E_USER_ERROR); /** * Falls Thread-Id noch nicht vorhanden, parent-id nehmen @@ -683,24 +698,22 @@ static function post($parent_id, $board, $user_id, $text, $msg_users=NULL) /** Nur weitermachen, wenn Rechte stimmen */ if (Thread::hasRights($board, $thread_id, $user_id)) { - /** - * Text escapen - * @FIXME use sanitize_userinput() instead of escape_text? See util.inc.php - */ - $text = escape_text($text); + /** Böse Sachen aus dem Text entfernen */ + $text = sanitize_userinput($text); /** Comment in die DB abspeichern */ $comment_error = (isset($comment_error) ? $comment_error : ''); - $comment_id = $db->insert('comments', ['user_id'=>$user_id, 'parent_id'=>$parent_id, 'thread_id'=>$thread_id, 'text'=>$text, 'date'=>'NOW()', 'board'=>$board, 'error'=>$comment_error], __FILE__, __LINE__, __METHOD__); + $comment_id = $db->insert('comments', ['user_id'=>$user_id, 'parent_id'=>$parent_id, 'thread_id'=>$thread_id, 'text'=>$text, 'date'=>timestamp(true), 'board'=>$board, 'error'=>$comment_error], __FILE__, __LINE__, __METHOD__); if(empty($comment_id) || !is_numeric($comment_id) || $comment_id <= 0) user_error(t('invalid-comment_id', 'commenting'), E_USER_ERROR); /** * Falls parent_id = 1, thread_id = id. * Für Forum->neue Threads. */ - $sql = 'UPDATE comments SET thread_id = id - WHERE parent_id = 1 AND board = "f" AND id = '.$comment_id; - $db->query($sql, __FILE__, __LINE__, __METHOD__); + $sql = 'UPDATE comments SET thread_id=id + WHERE parent_id=? AND board=? AND id=?'; + $params = [1, "f", $comment_id]; + $db->query($sql, __FILE__, __LINE__, __METHOD__, $params); $rs = self::getRecordset($comment_id); $commentlink = self::getLink($rs['board'], $rs['parent_id'], $rs['id'], $rs['thread_id']); @@ -710,20 +723,16 @@ static function post($parent_id, $board, $user_id, $text, $msg_users=NULL) if(empty($commentlink) || !$commentlink || is_numeric($commentlink)) user_error(t('invalid-comment_id', 'commenting'), E_USER_ERROR); /** Falls neuer Thread, Record in Thread-Tabelle generieren */ - $sql = sprintf('INSERT IGNORE INTO comments_threads (board, thread_id, comment_id) VALUES ("%s", %d, %d)', - $rs['board'], $rs['thread_id'], $rs['id']); - $db->query($sql, __FILE__, __LINE__, __METHOD__); + $sql = 'INSERT IGNORE INTO comments_threads (board, thread_id, comment_id) VALUES (?, ?, ?)'; + $params = [$rs['board'], $rs['thread_id'], $rs['id']]; // TODO use $db->insert('comments_threads', array(key=value)) instead of $db->query() + $db->query($sql, __FILE__, __LINE__, __METHOD__, $params); /** last post setzen */ $sql = 'UPDATE comments_threads - SET - last_comment_id = '.$rs['id'].' - , comment_id = IF(ISNULL(comment_id), '.$rs['id'].', comment_id) - WHERE - thread_id = '.$rs['thread_id'].' - AND board = "'.$board.'"'; - $db->query($sql, __FILE__, __LINE__, __METHOD__); + SET last_comment_id=?, comment_id=IF(ISNULL(comment_id), ?, comment_id) + WHERE thread_id=? AND board=?'; + $db->query($sql, __FILE__, __LINE__, __METHOD__, [$rs['id'], $rs['id'], $rs['thread_id'], $board]); /** Comment-Template kompilieren */ $compile_template_result = self::compile_template($rs['thread_id'], $rs['id'], $rs['board']); @@ -737,10 +746,10 @@ static function post($parent_id, $board, $user_id, $text, $msg_users=NULL) } /** Mark comment as unread for all users */ - self::markasunread($rs['id']); + $markedAsUnread = self::markasunread($rs['id']); /** Mark comment as read for poster (current user) */ - self::markasread($rs['id'], $user_id); + $markedReadForPoster = self::markasread($rs['id'], $user_id); /** * Comment Notifications @@ -781,8 +790,8 @@ static function post($parent_id, $board, $user_id, $text, $msg_users=NULL) } /** 3) Message an alle Subscriber senden */ - $sql = 'SELECT * FROM comments_subscriptions WHERE comment_id = '.$parent_id.' AND board="'.$board.'"'; - $result = $db->query($sql, __FILE__, __LINE__, __METHOD__); + $sql = 'SELECT * FROM comments_subscriptions WHERE comment_id=? AND board=?'; + $result = $db->query($sql, __FILE__, __LINE__, __METHOD__, [$parent_id, $board]); if($db->num($result) > 0) { $subject = t('message-newcomment-subscribed-subject', 'subscriptions', [ $user->id2user($user_id,true), $parent_id]); @@ -825,13 +834,13 @@ static function update($comment_id, $comment_data_updated) $sql = 'UPDATE comments SET - text="'.$_POST['text'].'" - , board="'.$_POST['board'].'" - , parent_id='.$_POST['parent_id'].' - , thread_id='.$_POST['thread_id'].' + text=? + , board=? + , parent_id=? + , thread_id=? , date_edited=NOW() - WHERE id = '.$comment_id.' AND board="'.$_POST['board'].'"'; - $db->query($sql, __FILE__, __LINE__, __METHOD__); + WHERE id = ? AND board=?'; + $db->query($sql, __FILE__, __LINE__, __METHOD__, [$_POST['text'], $_POST['board'], $_POST['parent_id'], $_POST['thread_id'], $comment_id, $_POST['board']]); /** Smarty Comment Templates neu Kompilieren */ self::compile_template($_POST['thread_id'], $comment_id, $_POST['board']); // sich selbst @@ -841,21 +850,21 @@ static function update($comment_id, $comment_data_updated) /** last post setzen */ $sql = 'UPDATE comments_threads - SET last_comment_id = (SELECT MAX(id) from comments WHERE thread_id = '.$_POST['thread_id'].' AND board = "'.$_POST['board'].'") - WHERE thread_id = '.$_POST['thread_id']; - $db->query($sql, __FILE__, __LINE__, __METHOD__); + SET last_comment_id=(SELECT MAX(id) FROM comments WHERE thread_id=? AND board=?) + WHERE thread_id=?'; + $db->query($sql, __FILE__, __LINE__, __METHOD__, [$_POST['thread_id'], $_POST['board'], $_POST['thread_id']]); /** Mark comment as unread for all users (again) */ - self::markasunread($comment_id); + $markedAsUnread = self::markasunread($comment_id); /** Mark comment as read for this user */ - self::markasread($comment_id, $user->id); + $markedReadForPoster = self::markasread($comment_id, $user->id); /** Message an alle gewünschten senden */ if(count($_POST['msg_users']) > 0) { $subject = t('message-commentupdate-subject', 'commenting', $user->id2user($user->id,true)); - $text = t('message-commentupdate', 'commenting', [ $user->id2user($user->id,true), addslashes(stripslashes($text)), self::getLink($_POST['board'], $_POST['parent_id'], $comment_id, $_POST['thread_id']) ]); + $text = t('message-commentupdate', 'commenting', [ $user->id2user($user->id,true), sanitize_userinput($_POST['text']), self::getLink($_POST['board'], $_POST['parent_id'], $comment_id, $_POST['thread_id']) ]); //for ($i=0; $i < count($_POST['msg_users']); $i++) { foreach ($_POST['msg_users'] as $msg_recipient_id) { @@ -903,12 +912,10 @@ static function deleteOldTemplates () { global $db, $smarty; $e = $db->query( - "SELECT c.id, c.board, c.thread_id - FROM comments c, comments_threads ct - WHERE c.thread_id = ct.thread_id AND ct.last_seen!='0000-00-00' - AND unix_timestamp(now())-unix_timestamp(ct.last_seen) > (60*60*24*".THREAD_TPL_TIMEOUT.")", - __FILE__, __LINE__ - ); + 'SELECT c.id, c.board, c.thread_id FROM comments c, comments_threads ct + WHERE c.thread_id=ct.thread_id AND ct.last_seen!=? + AND UNIX_TIMESTAMP(?)-UNIX_TIMESTAMP(ct.last_seen) > (60*60*24*?)', + __FILE__, __LINE__, __METHOD__, ["0000-00-00", timestamp(true), THREAD_TPL_TIMEOUT]); $anz = 0; while ($d = $db->fetch($e)) { $anz++; @@ -1072,9 +1079,9 @@ static function getBoardTitle($board) /** Validate passed $board */ if (empty($board) || is_numeric($board) || is_array($board)) return false; - $sql = 'SELECT title FROM comments_boards WHERE board = "'.$board.'" LIMIT 1'; - $rs = $db->fetch($db->query($sql, __FILE__, __LINE__)); - return $rs['title']; + $sql = 'SELECT title FROM comments_boards WHERE board=? LIMIT 1'; + $rs = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$board])); + return (isset($rs['title']) ? $rs['title'] : ''); } @@ -1299,10 +1306,10 @@ static function getUnreadLink() { , user.username FROM comments LEFT JOIN user on comments.user_id = user.id - LEFT JOIN comments_unread ON (comments.id=comments_unread.comment_id AND comments_unread.user_id='.$user->id.') + LEFT JOIN comments_unread ON (comments.id=comments_unread.comment_id AND comments_unread.user_id=?) WHERE comments_unread.comment_id IS NOT NULL ORDER by date ASC LIMIT 0,1'; - $rs2 = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__)); + $rs2 = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$user->id])); return Comment::getLink($rs2['board'], $rs2['parent_id'], $rs2['id'], $rs2['thread_id']); } @@ -1312,17 +1319,14 @@ static function getUnreadLink() { * @param $thread_id int * @return Array */ - static function getLastComment() { - global $db; - $sql = - "SELECT user.clan_tag, user.username, comments.*, UNIX_TIMESTAMP(date) as date" - ." FROM comments" - ." left join user on comments.user_id = user.id" - ." order by date desc Limit 0,1" - ; - $result = $db->query($sql, __FILE__, __LINE__, __METHOD__); - $rs = $db->fetch($result); - return $rs; + static function getLastComment() + { + global $db; + $sql = 'SELECT user.clan_tag, user.username, comments.*, UNIX_TIMESTAMP(date) as date + FROM comments LEFT JOIN user ON comments.user_id=user.id ORDER BY date DESC LIMIT 1'; + $result = $db->query($sql, __FILE__, __LINE__, __METHOD__); + $rs = $db->fetch($result); + return $rs; } static function getNavigation($page=1, $pagesize, $numpages) { @@ -1407,39 +1411,41 @@ static function printSearchedComments($keyword) * @TODO HTML => Smarty-Template & return with $smarty->fetch()... * @return String */ - static function getLatestComments($num=10, $title = '', $board = '') { - + static function getLatestComments($num=10, $title = '', $board = '') + { global $db, $user; - if (!$num) $num = 10; - - $wboard = ( $board ? 'comments.board="'.$board.'"' : '' ); + $limit = $num ? $num : 10; + $where_board = ( $board ? 'comments.board=?' : '' ); //beschränkt auf 365 tage, da sonst unglaublich lahm - $sql = - 'SELECT - comments.*, - IF(ISNULL(comments_unread.comment_id), 0, 1) AS isunread, - UNIX_TIMESTAMP(date) as date - FROM comments - LEFT JOIN user - ON comments.user_id = user.id - LEFT JOIN comments_threads ct - ON ct.thread_id = comments.thread_id - AND ct.board = comments.board - LEFT JOIN comments_threads_rights ctr - ON ctr.thread_id = comments.thread_id - AND ctr.board = comments.board - AND ctr.user_id = '.$user->id.' - LEFT JOIN comments_unread - ON (comments.id=comments_unread.comment_id - AND comments_unread.user_id = '.$user->id.') - WHERE '.( !empty($wboard) ? $wboard.' AND ' : '').'(user.usertype >= ct.rights OR ct.rights='.USER_SPECIAL.' AND ctr.user_id IS NOT NULL) - AND DATEDIFF(now(), date) < 365 - ORDER BY date desc LIMIT 0,'.$num - ; - - $result = $db->query($sql, __FILE__, __LINE__, __METHOD__); + $sql ='SELECT + comments.*, + IF(ISNULL(comments_unread.comment_id), 0, 1) AS isunread, + UNIX_TIMESTAMP(date) as date + FROM comments + LEFT JOIN user + ON comments.user_id = user.id + LEFT JOIN comments_threads ct + ON ct.thread_id = comments.thread_id + AND ct.board = comments.board + LEFT JOIN comments_threads_rights ctr + ON ctr.thread_id = comments.thread_id + AND ctr.board = comments.board + AND ctr.user_id = ? + LEFT JOIN comments_unread + ON (comments.id=comments_unread.comment_id + AND comments_unread.user_id=?) + WHERE '.( !empty($where_board) ? $where_board.' AND ' : '') + .'(user.usertype >= ct.rights OR ct.rights=? AND ctr.user_id IS NOT NULL) + AND DATEDIFF(now(), date) < 365 + ORDER BY date desc LIMIT ?'; + + $params = [$user->id, $user->id]; + if ($board) array_unshift($params, $board); + $params[] = USER_SPECIAL; + $params[] = $limit; + $result = $db->query($sql, __FILE__, __LINE__, __METHOD__, $params); $html .= '
' @@ -2419,24 +2425,18 @@ static function getLastComment($board, $thread_id) { * @return Array * @param int $thread_id int */ - static function getLastUnreadComment($board, $thread_id, $user_id) { + static function getLastUnreadComment($board, $thread_id, $user_id) + { global $db; - $sql = - " - SELECT - comments.* - , UNIX_TIMESTAMP(comments.date) as date - FROM comments - LEFT JOIN comments_unread - ON (comments.id = comments_unread.comment_id AND comments_unread.user_id = ".$user_id.") - WHERE - comments_unread.comment_id is NOT NULL - AND comments.thread_id = ".$thread_id." - AND comments.board='".$board."' - ORDER by date ASC LIMIT 0,1 - " - ; - return $db->fetch($db->query($sql, __FILE__, __LINE__)); + $sql = 'SELECT comments.*, UNIX_TIMESTAMP(comments.date) as date + FROM comments LEFT JOIN comments_unread + ON (comments.id = comments_unread.comment_id AND comments_unread.user_id=?) + WHERE + comments_unread.comment_id is NOT NULL + AND comments.thread_id=? + AND comments.board=? + ORDER by date ASC LIMIT 1'; + return $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$user_id, $thread_id, $board])); } /** @@ -2504,8 +2504,8 @@ static function getNumPosts($board, $thread_id) if (empty($board) || is_numeric($board) || is_bool($board)) return false; if (empty($thread_id) || !is_numeric($thread_id) || $thread_id <= 0) return false; - $sql = 'SELECT id FROM comments WHERE thread_id = '.$thread_id.' AND board="'.$board.'"'; - return $db->num($db->query($sql, __FILE__, __LINE__, __METHOD__)); + $sql = 'SELECT id FROM comments WHERE thread_id=? AND board=?'; + return $db->num($db->query($sql, __FILE__, __LINE__, __METHOD__, [$thread_id, $board])); } /** @@ -2546,9 +2546,8 @@ static function getNumUnread ($board, $thread_id, $user_id=null) { $sql = 'SELECT count(c.id) anz FROM comments c, comments_unread u - WHERE c.board = "'.$board.'" AND c.thread_id='.$thread_id.' AND u.comment_id=c.id AND u.user_id='.$user_id - ; - $d = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__)); + WHERE c.board=? AND c.thread_id=? AND u.comment_id=c.id AND u.user_id=?'; + $d = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$board, $thread_id, $user_id])); return $d['anz']; } @@ -2571,9 +2570,8 @@ static function getRecordset($board, $thread_id) { if (empty($board) || is_numeric($board) || is_array($board)) return false; if (empty($thread_id) || !is_numeric($thread_id) || $thread_id <= 0 || is_array($thread_id)) return false; - $sql = 'SELECT *, UNIX_TIMESTAMP(date) as date - FROM comments where thread_id='.$thread_id.' and board="'.$board.'"'; - return $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__)); + $sql = 'SELECT *, UNIX_TIMESTAMP(date) as date FROM comments where thread_id=? and board=?'; + return $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$thread_id, $board])); } /** @@ -2595,23 +2593,22 @@ static function printChildPosts($board, $parent_id, $depth=array("space")) { } $hierdepth = count($depth); - $sql = - "SELECT" - ." comments.*" - .", user.clan_tag, user.username" - .", comments_unread.user_id as isunread" - .", UNIX_TIMESTAMP(comments.date) as date" - .", count(c2.id) as numchildposts" - ." FROM comments" - ." LEFT JOIN comments_unread ON (comments.id=comments_unread.comment_id AND comments_unread.user_id = '".$_SESSION['user_id']."')" - ." LEFT JOIN user ON comments.user_id = user.id" - ." LEFT JOIN comments as c2 ON (comments.id = c2.parent_id AND comments.board = c2.board)" - ." WHERE comments.parent_id = $parent_id AND comments.board = '".$board."'" - ." GROUP BY comments.id" - ." ORDER BY comments.id" - ; + $sql = 'SELECT + comments.* + ,user.clan_tag, user.username + ,comments_unread.user_id as isunread + ,UNIX_TIMESTAMP(comments.date) as date + ,count(c2.id) as numchildposts + FROM comments + LEFT JOIN comments_unread ON (comments.id=comments_unread.comment_id AND comments_unread.user_id=?) + LEFT JOIN user ON comments.user_id=user.id + LEFT JOIN comments as c2 ON (comments.id=c2.parent_id AND comments.board=c2.board) + WHERE comments.parent_id=? AND comments.board=? + GROUP BY comments.id + ORDER BY comments.id + '; - $result = $db->query($sql, __FILE__, __LINE__, __METHOD__); + $result = $db->query($sql, __FILE__, __LINE__, __METHOD__, [$user->id, $parent_id, $board]); $rcount = 0; $additional = FALSE; // already posted "Additional Posts" ? while($rs = $db->fetch($result)) { diff --git a/www/includes/gallery.inc.php b/www/includes/gallery.inc.php index 557c4a4..595f33d 100644 --- a/www/includes/gallery.inc.php +++ b/www/includes/gallery.inc.php @@ -3,49 +3,44 @@ * Gallery Funktionen * * Beinhaltet alle Funktionen der Gallery. + * @TODO Move LAYOUT FUNCTIONS to Template Engine + * @TODO Wasserzeichen(?) * - * @author [z]biko - * @package zorg\Gallery - * @version 3.0 - * @since 1.0 File & functions added + * @version 3.5 + * @since 1.0 `[z]biko` File added * @since 2.0 Added code documentations, polished & optimized various functions * @since 3.0 `09.08.2018` `IneX` Refactored picPath() & createPic(), added APOD specific specials + * @since 3.5 `24.12.2023` `IneX` Code optimizations and refactorings * - * @TODO MyPic-Markierung von Bildern - * @TODO Wasserzeichen(?) + * @package zorg\Gallery */ + +/** + * Configs + * + * set_time_limit Maximale Zeit in Sekunden, welche das Script laufen darf + */ +set_time_limit(600); + /** * File includes * @include config.inc.php * @include forum.inc.php - * @include util.inc.php + * @include util.inc.php DISABLED is part of config.inc.php * @include usersystem.inc.php */ require_once dirname(__FILE__).'/config.inc.php'; include_once INCLUDES_DIR.'forum.inc.php'; -require_once INCLUDES_DIR.'util.inc.php'; +//require_once INCLUDES_DIR.'util.inc.php'; require_once INCLUDES_DIR.'usersystem.inc.php'; -/** - * @const set_time_limit Maximale Zeit in Sekunden, welche das Script laufen darf - * @const FTP_UPDIT FTP-Serveraddress and Directory-Path to Gallery Upload Dir - * @const DIR Path to Gallery directory on the server - * @const UPDIR Path to the Upload directory on the server - * @const ZENSUR If the User is a Member, he can see censored Pics. Otherwise the SQL-Query addition will filter them out. - */ -set_time_limit(600); -define('FTP_UPDIR', 'ftp://zooomclan@zorg.ch/data/gallery/upload/incoming/'); // @DEPRECATED -define('DIR', $_SERVER['DOCUMENT_ROOT'].'/../data/gallery/'); // @DEPRECATED Replaced with GALLERY_DIR in config.inc.php -define('UPDIR', $_SERVER['DOCUMENT_ROOT'].'/../data/upload/'); // @DEPRECATED Replaced with GALLERY_UPLOAD_DIR in config.inc.php -define('ZENSUR', ( $user->typ >= USER_MEMBER ? '' : 'AND p.zensur="0"' )); - /** * Globals - * @var array $MAX_PIC_SIZE The maximum width & height for pictures - * @var array $THUMBPAGE The image size for Thumbnail pictures + * @const ZENSUR SQL-Query addition if the User is a Member (it can see censored Pics), otherwise filter them out. + * @const THUMBPAGE The number of Thumbnail pictures per column and page (rows) when rendering the layout */ -$MAX_PIC_SIZE = array('picWidth'=>800, 'picHeight'=>800, 'tnWidth'=>150, 'tnHeight'=>150); -$THUMBPAGE = array('width'=>4, 'height'=>3, 'padding'=>10); +define('ZENSUR', ($user->typ >= USER_MEMBER ? '' : 'AND p.zensur="0"')); +define('THUMBPAGE', ['cols'=>4, 'rows'=>3, 'padding'=>10]); // ********************************** LAYOUT FUNCTIONS *************************************************************************** @@ -54,23 +49,21 @@ * * Zeigt die Gallery-Ãœbersicht mit allen Alben * - * @author [z]biko - * @version 1.0 - * @since 1.0 function added + * @version 1.5 + * @since 1.0 `[z]biko` function added + * @since 1.5 `24.12.2023` `IneX` Optimizations and refactorings * + * @uses USER_MEMBER, ZENSUR * @param string $state Aktueller Status des Albums, z.B. wenn es gerade bearbeitet wird * @param string $error (Fehler-)Meldung, welche auf der Gallery-Seite angezeigt werden soll * @global object $db Globales Class-Object mit allen MySQL-Methoden * @global object $user Globales Class-Object mit den User-Methoden & Variablen * @global object $smarty Globales Class-Object mit allen Smarty-Methoden - * @global array $MAX_PIC_SIZE Variable mit den Werten aus $MAX_PIC_SIZE - * @global array $THUMBPAGE Variable mit den Werten aus $THUMBPAGE - * @uses USER_MEMBER, ZENSUR * @return string HTML-Code der Gallery-Seite */ function galleryOverview ($state="", $error="") { - global $db, $user, $MAX_PIC_SIZE, $THUMBPAGE, $smarty; + global $db, $user, $smarty; /** Error Output (function backwards compatibility) */ if ((isset($state) || isset($error)) && $user->typ >= USER_MEMBER) @@ -145,40 +138,38 @@ function galleryOverview ($state="", $error="") /** * Album Thumbnails anzeigen * - * @version 2.0 + * @version 2.1 * @since 1.0 function added * @since 1.5 moved pagination to new Sidebar, output it via $smarty * @since 2.0 `16.12.2022` `IneX` lazy-loaded responsive Gallery Album Thumbs Overview + * @since 2.1 `24.12.2023` `IneX` Optimizations and refactorings * * @param integer $id ID des Albums von welchem die Thumbnails angezeigt werden sollen * @param integer $page Aktuelle Seite des Albums, deren Thumbnails angezeigt werden sollen * @global object $db Globales Class-Object mit allen MySQL-Methoden * @global object $user Globales Class-Object mit den User-Methoden & Variablen * @global object $smarty Globales Class-Object mit allen Smarty-Methoden - * @global array $MAX_PIC_SIZE Variable mit den Werten aus $MAX_PIC_SIZE - * @global array $THUMBPAGE Variable mit den Werten aus $THUMBPAGE - * @uses ZENSUR + * @uses THUMBPAGE, ZENSUR * @uses user_error(), self::imgsrcThum(), Thread::getNumPosts(), Thread::getNumUnread() */ -function albumThumbs ($id, $page=0) { - global $db, $THUMBPAGE, $MAX_PIC_SIZE, $user, $smarty; +function albumThumbs ($id, $page=0) +{ + global $db, $user, $smarty; - if (!is_numeric($id) || $id <= 0) - { - user_error('Missing Parameter id', E_USER_ERROR); - exit; - } + if (!is_numeric($id) || $id <= 0) user_error('Missing Parameter id', E_USER_ERROR); + if (!is_numeric($page) || $page < 0) user_error('Missing Parameter page', E_USER_ERROR); - $pagepics = $THUMBPAGE['width'] * $THUMBPAGE['height']; + $pagepics = THUMBPAGE['cols'] * THUMBPAGE['rows']; $e = $db->query('SELECT count(id) anz FROM gallery_pics p WHERE album='.$id.' '.ZENSUR.' GROUP BY album', __FILE__, __LINE__, __FUNCTION__); - $d = mysqli_fetch_array($e); + $d = $db->fetch($e); $anz = $d['anz']; $htmlOutput = null; $sidebarHtml = null; if (!empty($d) && $d['anz'] > 0) { - $e = $db->query(sprintf('SELECT g.id, g.name, IF(e.enddate != "0000-00-00 00:00:00" AND g.created IS NULL, e.enddate, g.created) created, e.id eventid, e.name eventname, GROUP_CONCAT(eu.user_id SEPARATOR ",") beenthere_users + $e = $db->query(sprintf('SELECT + g.id, g.name, IF(e.enddate != "0000-00-00 00:00:00" AND g.created IS NULL, e.enddate, g.created) created, e.id eventid, e.name eventname, GROUP_CONCAT(eu.user_id SEPARATOR ",") beenthere_users FROM gallery_albums g LEFT JOIN events e ON e.gallery_id=g.id LEFT JOIN events_to_user eu ON eu.event_id=e.id WHERE g.id=%d GROUP BY g.id, e.enddate, e.id, e.name', $id), __FILE__, __LINE__, __FUNCTION__); $d = $db->fetch($e); @@ -186,8 +177,8 @@ function albumThumbs ($id, $page=0) { if ($user->typ == USER_MEMBER) $htmlOutput .= '

[edit name] [add pics]

'; $e = $db->query('SELECT * FROM gallery_pics p WHERE album='.$id.' '.ZENSUR.' ORDER BY p.id LIMIT '.($page*$pagepics).', '.$pagepics, __FILE__, __LINE__, __FUNCTION__); - $hgt = $MAX_PIC_SIZE['tnHeight'] + 2 * $THUMBPAGE['padding']; - $wdt = $MAX_PIC_SIZE['tnWidth'] + 2 * $THUMBPAGE['padding']; + // $hgt = MAX_THUMBNAIL_SIZE['height'] + 2 * THUMBPAGE['padding']; + // $wdt = MAX_THUMBNAIL_SIZE['width'] + 2 * THUMBPAGE['padding']; $rows = 1; $htmlOutput .= '
'; while ($pic = $db->fetch($e)) @@ -247,37 +238,33 @@ function albumThumbs ($id, $page=0) { /** * Bild anzeigen * - * @author [z]biko - * @author IneX - * @version 2.4 + * @version 2.5 * @since 1.0 `21.10.2013` `[z]biko` function added * @since 2.0 `01.10.2019` `IneX` APOD Special: statt Pic ein Video embedden * @since 2.1 `01.10.2019` `IneX` responsive scaling `img` and