Compare commits
304 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f8252e4425 | ||
![]() |
2616a68778 | ||
![]() |
793ae79e6c | ||
![]() |
3a6fcb6366 | ||
![]() |
3681e2264b | ||
![]() |
4294c9bfa3 | ||
![]() |
610ef1deb2 | ||
![]() |
f431c3b69e | ||
![]() |
14cced79f9 | ||
![]() |
1fa288198a | ||
![]() |
1ddf88519a | ||
![]() |
a42f472301 | ||
![]() |
9c13d4cff4 | ||
![]() |
af4ac289f9 | ||
![]() |
7c74e2e080 | ||
![]() |
19f8763129 | ||
![]() |
673492abe8 | ||
![]() |
5c0af81225 | ||
![]() |
f5a90ebcd6 | ||
![]() |
03afea0772 | ||
![]() |
ea809f670c | ||
![]() |
bfdca5deff | ||
![]() |
1fac38bd54 | ||
![]() |
ebc9028fb9 | ||
![]() |
c19e83bfa9 | ||
![]() |
a76cebf46f | ||
![]() |
fc763d96d1 | ||
![]() |
003d978b38 | ||
![]() |
7384f93f4a | ||
![]() |
bbe62bc134 | ||
![]() |
62d45a9fd9 | ||
![]() |
09c725c451 | ||
![]() |
0b94e0f789 | ||
![]() |
200fd93450 | ||
![]() |
779130c08f | ||
![]() |
352e5f44c4 | ||
![]() |
941442f5ea | ||
![]() |
0b66c3f7c6 | ||
![]() |
d5426fe324 | ||
![]() |
33fe810af1 | ||
![]() |
4274601a2c | ||
![]() |
28bba299ba | ||
![]() |
44a321fd9e | ||
![]() |
1de0d48e1d | ||
![]() |
9b6a4ae061 | ||
![]() |
49ce8a95d6 | ||
![]() |
c978a35134 | ||
![]() |
204563ba11 | ||
![]() |
d0909b42ca | ||
![]() |
28837c75aa | ||
![]() |
94ff35cc9f | ||
![]() |
dd583f55cd | ||
![]() |
c0c67c8956 | ||
![]() |
b3e8da9149 | ||
![]() |
cc26a494cb | ||
![]() |
f3e5fdd2b2 | ||
![]() |
27975e72e8 | ||
![]() |
c3d3580498 | ||
![]() |
f71d25067b | ||
![]() |
e7c4468d29 | ||
![]() |
fe1d1d93eb | ||
![]() |
12cce10500 | ||
![]() |
f4afe87a3d | ||
![]() |
7e49c50bc0 | ||
![]() |
e2999844dd | ||
![]() |
8254167cc2 | ||
![]() |
36cabb1fcd | ||
![]() |
e98571db9e | ||
![]() |
4a9597ab3c | ||
![]() |
879f93b826 | ||
![]() |
19c30e044c | ||
![]() |
58a2786a14 | ||
![]() |
47991395af | ||
![]() |
3d850bd348 | ||
![]() |
d375fee38c | ||
![]() |
ad566db4d5 | ||
![]() |
1082e20b7b | ||
![]() |
6cd8e71916 | ||
![]() |
e190ed45a0 | ||
![]() |
201730adbe | ||
![]() |
d57980783d | ||
![]() |
a85af1bf18 | ||
![]() |
b1be8cbef7 | ||
![]() |
4821839b5c | ||
![]() |
d1a1206f8c | ||
![]() |
1ceacda262 | ||
![]() |
d9b8ff2ca0 | ||
![]() |
04864fa8eb | ||
![]() |
b0075a9f43 | ||
![]() |
91d9cffc29 | ||
![]() |
d112eaa7c7 | ||
![]() |
45cbebe978 | ||
![]() |
c5180cec26 | ||
![]() |
a234af3645 | ||
![]() |
0051501576 | ||
![]() |
8c67f1ec0d | ||
![]() |
55636553a5 | ||
![]() |
dcc4ab0d24 | ||
![]() |
a5e658218d | ||
![]() |
33a6e7e2fc | ||
![]() |
d38e64a717 | ||
![]() |
f140db4c28 | ||
![]() |
e924a68057 | ||
![]() |
5ff3d7b351 | ||
![]() |
58a85b4bb3 | ||
![]() |
efc0417c8a | ||
![]() |
a05da69b33 | ||
![]() |
1a85248e61 | ||
![]() |
4ec93dcdef | ||
![]() |
cf086d358c | ||
![]() |
822744611f | ||
![]() |
f4f6772e1d | ||
![]() |
6c3dd07040 | ||
![]() |
0d4bbb5e40 | ||
![]() |
264e278c4c | ||
![]() |
ccf1dbf54e | ||
![]() |
9f37c75096 | ||
![]() |
4dbbf40c6e | ||
![]() |
3a94acccad | ||
![]() |
5805ab41d8 | ||
![]() |
992505172f | ||
![]() |
dac7c3c1ba | ||
![]() |
cb1f4bbdf2 | ||
![]() |
19b5bc9eb7 | ||
![]() |
415ec17b72 | ||
![]() |
8a218658a6 | ||
![]() |
511a3b0531 | ||
![]() |
9ec1fa358e | ||
![]() |
06ba72b1e6 | ||
![]() |
242472cc81 | ||
![]() |
a0bf03c9e2 | ||
![]() |
23a025137e | ||
![]() |
48c1120241 | ||
![]() |
a34e0f53eb | ||
![]() |
4fd35d642a | ||
![]() |
03c1b66c70 | ||
![]() |
648ef10ab6 | ||
![]() |
1aa2a1578f | ||
![]() |
975880f637 | ||
![]() |
4cbc55f0ce | ||
![]() |
ec6921bbd7 | ||
![]() |
b26a044b77 | ||
![]() |
66580c5a71 | ||
![]() |
e31f3e5cd6 | ||
![]() |
174b60c371 | ||
![]() |
7c52ba9a27 | ||
![]() |
893ddf63f9 | ||
![]() |
e8a5ee85e2 | ||
![]() |
b33b45b197 | ||
![]() |
f0089f7ff9 | ||
![]() |
550d70564b | ||
![]() |
3c9ac61691 | ||
![]() |
c789bde9ad | ||
![]() |
74c36ee5bd | ||
![]() |
d76d670b1a | ||
![]() |
c575ffc744 | ||
![]() |
fc6840769f | ||
![]() |
c337df2df1 | ||
![]() |
fbbf89fab7 | ||
![]() |
b56675d95b | ||
![]() |
48532249ec | ||
![]() |
ff17798ce2 | ||
![]() |
e74e4b3695 | ||
![]() |
36e2d34cee | ||
![]() |
28cf0b4937 | ||
![]() |
909533a984 | ||
![]() |
5b880f1f16 | ||
![]() |
5452768a82 | ||
![]() |
8050e80553 | ||
![]() |
9d29488894 | ||
![]() |
041427dc68 | ||
![]() |
9fa757fc7e | ||
![]() |
7707108a22 | ||
![]() |
3af8bbd8db | ||
![]() |
d99fce555e | ||
![]() |
1116aa3b11 | ||
![]() |
8dc98ebeae | ||
![]() |
a0bec132b3 | ||
![]() |
7ac18b725b | ||
![]() |
51371c59fa | ||
![]() |
ea19ceabf2 | ||
![]() |
513dbe49a2 | ||
![]() |
f8f94bad00 | ||
![]() |
9b12884cdb | ||
![]() |
91b38e4f9f | ||
![]() |
5d730d00ac | ||
![]() |
570326c946 | ||
![]() |
cddb893f6c | ||
![]() |
ce75af0197 | ||
![]() |
f07d42db2c | ||
![]() |
4333ce57c1 | ||
![]() |
1615c078e2 | ||
![]() |
5fa5c9df58 | ||
![]() |
3d08eeef91 | ||
![]() |
5cfcf45834 | ||
![]() |
8ee02c6a9e | ||
![]() |
289c728b5b | ||
![]() |
17d274a4db | ||
![]() |
7280704638 | ||
![]() |
9b8e235563 | ||
![]() |
2e3d9b1051 | ||
![]() |
3f8b83b264 | ||
![]() |
d3b1ab9429 | ||
![]() |
c7ba7d09d9 | ||
![]() |
3c128e6f5b | ||
![]() |
dd8006b2ac | ||
![]() |
24248776f0 | ||
![]() |
0c02740618 | ||
![]() |
d318877a0b | ||
![]() |
b1f1fe494b | ||
![]() |
1f0228c03a | ||
![]() |
76811ea9ce | ||
![]() |
e093329b2e | ||
![]() |
0d95fbcbc7 | ||
![]() |
daf564afbc | ||
![]() |
5331d07263 | ||
![]() |
ad1d20a16f | ||
![]() |
79908f73d8 | ||
![]() |
d6f85509be | ||
![]() |
71973b4c6b | ||
![]() |
53d289cb85 | ||
![]() |
70b9016b60 | ||
![]() |
aef8a4b4f3 | ||
![]() |
b0700f5587 | ||
![]() |
2bd70e4f33 | ||
![]() |
224c1abc7c | ||
![]() |
f3be68cef2 | ||
![]() |
6bd7f6b69b | ||
![]() |
5510aaff13 | ||
![]() |
b86f02e2bb | ||
![]() |
bc9a5f75be | ||
![]() |
4080cc7fc8 | ||
![]() |
20e19a70ec | ||
![]() |
5a327ca6cf | ||
![]() |
f7749217e9 | ||
![]() |
dcf3496e7f | ||
![]() |
07bb91c402 | ||
![]() |
8b0e44a26c | ||
![]() |
83c8fb864f | ||
![]() |
aa6f0fccd0 | ||
![]() |
cdf84b65e6 | ||
![]() |
2de440411d | ||
![]() |
6bbc4023ff | ||
![]() |
eebe724c27 | ||
![]() |
be6a8a8c53 | ||
![]() |
ebd02dc2e0 | ||
![]() |
7ccfb9e5ad | ||
![]() |
57a136a601 | ||
![]() |
09c19cf660 | ||
![]() |
7ffabf79f8 | ||
![]() |
dcc8309ef5 | ||
![]() |
9de9c5b03d | ||
![]() |
36593471d4 | ||
![]() |
b99f9db280 | ||
![]() |
9038726dc4 | ||
![]() |
d45f71bce5 | ||
![]() |
e80111c1be | ||
![]() |
2beb107670 | ||
![]() |
7570356c4d | ||
![]() |
06091a2753 | ||
![]() |
f1845a4afe | ||
![]() |
47e6202508 | ||
![]() |
8a71b2ca02 | ||
![]() |
62d454dec5 | ||
![]() |
b2342b2192 | ||
![]() |
6218082614 | ||
![]() |
90d42535a7 | ||
![]() |
a4fcef9e29 | ||
![]() |
eab4721259 | ||
![]() |
76b941a7a4 | ||
![]() |
81856fd767 | ||
![]() |
986a88a0cf | ||
![]() |
a584d07d9b | ||
![]() |
fbb73944d7 | ||
![]() |
41e5090397 | ||
![]() |
6938c6ead3 | ||
![]() |
df1f2bd406 | ||
![]() |
31ccd56592 | ||
![]() |
17a85077f6 | ||
![]() |
51481cdf68 | ||
![]() |
81ab966624 | ||
![]() |
a2ab5fb039 | ||
![]() |
9cd486f86b | ||
![]() |
49e00cdc15 | ||
![]() |
49eff28e3f | ||
![]() |
3bc7e284c0 | ||
![]() |
a03dbd394d | ||
![]() |
4f319c045e | ||
![]() |
22704b977b | ||
![]() |
bc669ed3dc | ||
![]() |
1f50e70f10 | ||
![]() |
bdbaa428a5 | ||
![]() |
8a7e446675 | ||
![]() |
40f2f9d8e4 | ||
![]() |
f44efed6cf | ||
![]() |
e28dc48e60 | ||
![]() |
67198b5d34 | ||
![]() |
23175e3131 | ||
![]() |
feea9a4233 | ||
![]() |
03e2c1d061 | ||
![]() |
9aa18e9b9e | ||
![]() |
d1379a3a97 | ||
![]() |
454fca732a | ||
![]() |
3c3e26b846 |
22
.github/workflows/phpcs.yml
vendored
|
@ -1,16 +1,10 @@
|
|||
# This is a basic workflow to help you get started with Actions
|
||||
name: PHP_CodeSniffer
|
||||
name: PHP_CodeSniffer - Qualité du code
|
||||
|
||||
# Controls when the action will run.
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the main branch
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
# Triggers the workflow on push or pull request events
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
|
@ -22,13 +16,15 @@ jobs:
|
|||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.0'
|
||||
php-version: '8.3'
|
||||
tools: cs2pr, phpcs
|
||||
|
||||
- name: Run phpcs
|
||||
run: phpcs -q --standard=$GITHUB_WORKSPACE/.phpcs_ruleset.xml --report=checkstyle $GITHUB_WORKSPACE | cs2pr
|
||||
run: |
|
||||
phpcs --version
|
||||
phpcs -q --standard=$GITHUB_WORKSPACE/.phpcs_ruleset.xml --report=checkstyle $GITHUB_WORKSPACE | cs2pr
|
73
.github/workflows/phpunit.yml
vendored
|
@ -1,38 +1,57 @@
|
|||
name: Tests de l'application
|
||||
on: [push, pull_request]
|
||||
name: PHPUnit - Tests de l'application
|
||||
on: [ push, pull_request, workflow_dispatch ]
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['7.3', '7.4', '8.0']
|
||||
matrix:
|
||||
php-versions: [ '8.3', '8.4' ]
|
||||
name: PHP ${{ matrix.php-versions }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configuration PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: phpunit
|
||||
- name: Configuration PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: imagick, pdo_mysql
|
||||
tools: phpunit
|
||||
ini-values: error_reporting=E_ALL, display_errors=On
|
||||
|
||||
- name: Lancement de MySQL
|
||||
run: sudo /etc/init.d/mysql start
|
||||
- name: Lancement de MySQL
|
||||
run: sudo systemctl start mysql.service
|
||||
|
||||
- name: Informations sur l'environnement
|
||||
run: |
|
||||
php --version
|
||||
mysql -V
|
||||
phpunit --version
|
||||
|
||||
- name: Mise en place de l'environnement
|
||||
run: |
|
||||
mysql -u root -proot -e "CREATE DATABASE imageheberg;"
|
||||
mysql -u root -proot imageheberg < database.sql
|
||||
sh -c "mv __tests/config/config.php config/"
|
||||
mysql -u root -proot imageheberg < __tests/data.sql
|
||||
- name: Informations sur l'environnement
|
||||
run: |
|
||||
php --version
|
||||
mysql -V
|
||||
phpunit --version
|
||||
php -r 'echo Imagick::getVersion()["versionString"];'
|
||||
php -r 'echo phpinfo();'
|
||||
mysql -u root -proot -e "SELECT @@GLOBAL.sql_mode global, @@SESSION.sql_mode session"
|
||||
|
||||
- name : Test de l'application
|
||||
run: phpunit --colors --debug __tests/
|
||||
- name: Mise en place de l'environnement
|
||||
run: |
|
||||
mysql -u root -proot -e "SET GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION';"
|
||||
mysql -u root -proot -e "alter user 'root'@'localhost' identified with mysql_native_password by 'root';"
|
||||
mysql -u root -proot -e "CREATE DATABASE imageheberg;"
|
||||
mysql -u root -proot imageheberg < database.sql
|
||||
sh -c "mv __tests/config/config.php config/"
|
||||
sh -c "mv __tests/ipv*.txt files/z_cache/"
|
||||
|
||||
# Pour ImageUploadAndDeleteTest
|
||||
sh -c "find files/ -name _dummy -type f -delete"
|
||||
|
||||
# Pour AbuseTest
|
||||
sh -c "mv __tests/images/image_33.png files/d/d0a77eeeff5ef764505fe5b119b913bf"
|
||||
|
||||
# Injection des données
|
||||
mysql -u root -proot imageheberg < __tests/data.sql
|
||||
|
||||
# Adaptation à l'environnement actuel
|
||||
php '__tests/_bootstrap.php'
|
||||
- name: Test de l'application - phpunit v11
|
||||
if: ${{ matrix.php-versions != '8.0' }}
|
||||
run: phpunit --colors --display-warnings --display-errors __tests/
|
||||
|
|
38
.htaccess
|
@ -1,5 +1,5 @@
|
|||
#/*
|
||||
#* Copyright 2008-2020 Anael MOBILIA
|
||||
#* Copyright 2008-2024 Anael MOBILIA
|
||||
#*
|
||||
#* This file is part of image-heberg.fr.
|
||||
#*
|
||||
|
@ -23,29 +23,27 @@ Options -Indexes
|
|||
# Ré-écriture d'URL
|
||||
RewriteEngine On
|
||||
|
||||
# Redirection systématique - si requise - vers www.image-heberg.fr
|
||||
# HTTPS
|
||||
RewriteCond %{HTTPS} on
|
||||
# Redirection systématique - si requise - vers **www**.image-heberg.fr
|
||||
RewriteCond %{HTTP_HOST} image-heberg\.fr\.cr [NC,OR]
|
||||
RewriteCond %{HTTP_HOST} ^image-heberg\.fr [NC]
|
||||
RewriteRule (.*) https://www.image-heberg.fr/$1 [R=301,L,NE]
|
||||
# HTTP
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteCond %{HTTP_HOST} image-heberg\.fr\.cr [NC,OR]
|
||||
RewriteCond %{HTTP_HOST} ^image-heberg\.fr [NC]
|
||||
RewriteRule (.*) https://www.image-heberg.fr/$1 [R=301,L,NE]
|
||||
|
||||
# Protection des répertoires classes, config, __tests
|
||||
RewriteCond %{REQUEST_URI} ^/classes/ [OR]
|
||||
RewriteCond %{REQUEST_URI} ^/config/ [OR]
|
||||
RewriteCond %{REQUEST_URI} ^/__tests/
|
||||
RewriteRule .* - [F]
|
||||
|
||||
# Images : redirection pour affichage
|
||||
RewriteCond %{REQUEST_URI} ^/files/
|
||||
RewriteRule .* displayPics.php [END]
|
||||
|
||||
# HTTPS obligatoire pour le site (hors affichage image)
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteCond %{REQUEST_URI} !^/files/
|
||||
RewriteRule (.*) https://www.image-heberg.fr/$1 [R=301,L,NE]
|
||||
RewriteRule (.*) https://www.image-heberg.fr/$1 [R=301,L,NE]
|
||||
|
||||
# Protection des répertoires classes, config, cron, __tests
|
||||
RewriteCond %{REQUEST_URI} ^/classes/ [OR]
|
||||
RewriteCond %{REQUEST_URI} ^/config/ [OR]
|
||||
RewriteCond %{REQUEST_URI} ^/cron/ [OR]
|
||||
RewriteCond %{REQUEST_URI} ^/__tests/
|
||||
RewriteRule .* - [F]
|
||||
|
||||
# Bootstrap icons - fichiers de fonts
|
||||
RewriteCond %{REQUEST_URI} ^/template/css/fonts/
|
||||
RewriteRule .*/(fonts/.*) https://www.image-heberg.fr/template/$1 [L,NE]
|
||||
|
||||
# Images : redirection pour affichage
|
||||
RewriteCond %{REQUEST_URI} ^/files/
|
||||
RewriteRule .* displayPics.php [END]
|
|
@ -2,7 +2,7 @@
|
|||
<ruleset name="myRuleset">
|
||||
<description>Regles pour le projet.</description>
|
||||
|
||||
<!-- Ne pas traiter les ficheirs minifiés -->
|
||||
<!-- Ne pas traiter les fichiers minifiés -->
|
||||
<exclude-pattern>*.min.*</exclude-pattern>
|
||||
<!-- Inclure PSR-12 -->
|
||||
<rule ref="PSR12">
|
||||
|
@ -10,5 +10,11 @@
|
|||
<exclude name="Generic.Files.LineEndings.InvalidEOLChar" />
|
||||
<!-- Exclure la longueur des lignes -->
|
||||
<exclude name="Generic.Files.LineLength.TooLong" />
|
||||
|
||||
</rule>
|
||||
</ruleset>
|
||||
<!-- Exclure les fichiers de conf qui ont un require sur le fichier générique à la fin -->
|
||||
<rule ref="PSR1.Files.SideEffects.FoundWithSymbols">
|
||||
<exclude-pattern>*/config/*.php</exclude-pattern>
|
||||
<exclude-pattern>*/cron/*.php</exclude-pattern>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
|
12
README.md
|
@ -3,7 +3,8 @@
|
|||
Service d'hébergement d'images en ligne
|
||||
|
||||
# Configuration requise
|
||||
- PHP 7.3, 7.4 [*(Préférez une version de PHP maintenue !)*](https://www.php.net/supported-versions.php)
|
||||
- PHP 8.3 [*(Préférez une version de PHP maintenue !)*](https://www.php.net/supported-versions.php)
|
||||
- Imagick
|
||||
- MySQL ou MariaDB
|
||||
- Serveur web gérant les fichiers .htaccess
|
||||
|
||||
|
@ -12,10 +13,13 @@ Service d'hébergement d'images en ligne
|
|||
- Copier les fichiers dans le répertoire du serveur web
|
||||
- Renommer le fichier config_empty.php en config.php et compléter les différents champs
|
||||
- Ajouter votre favicon dans template/images/monSite.ico
|
||||
- Ajouter votre css dans dans template/css/monSite.css
|
||||
- Ajouter votre css dans template/css/monSite.css
|
||||
- Configurer l'URL du site dans le fichier .htaccess
|
||||
- Valider l'installation de base en appelant le fichier install.php (example.com/install.php).
|
||||
- Se connecter avec le compte admin / password. Ce compte est le compte de l'administrateur du site. (pensez à mettre à jour l'adresse mail associée !)
|
||||
- Valider l'installation de base en appelant le fichier install.php (example.com/install.php)
|
||||
- Mettre en place un cron sur cron/updateTorIp.php, cron/cleanImages.php, cron/cleanAccounts.php, cron/abuse.php
|
||||
- Se connecter avec le compte admin / password. Ce compte est le compte de l'administrateur du site.
|
||||
- Modifier le mot de passe du compte
|
||||
- Mettre à jour l'adresse email associée
|
||||
|
||||
# Changer de thème
|
||||
- Choisir un thème sur [bootswatch](https://bootswatch.com/)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,44 +21,435 @@
|
|||
|
||||
namespace ImageHebergTests;
|
||||
|
||||
use ImageHeberg\HelperAbuse;
|
||||
use ImageHeberg\ImageObject;
|
||||
use ImageHeberg\MaBDD;
|
||||
use ImageHeberg\MetaObject;
|
||||
use ImageHeberg\MiniatureObject;
|
||||
use ImageHeberg\Outils;
|
||||
use ImageHeberg\RessourceInterface;
|
||||
use ImageHeberg\HelperAdmin;
|
||||
use ImageHeberg\RessourceObject;
|
||||
use ImageHeberg\SessionObject;
|
||||
use ImageHeberg\UtilisateurObject;
|
||||
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AbuseTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* Signalement d'une image
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testAbuse()
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuse(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_POST['Submit'] = 1;
|
||||
$_SESSION['flag'] = true;
|
||||
$_POST['userMail'] = "john.doe@example.com";
|
||||
$_POST['urlImage'] = "http://www.example.com/files/15.png";
|
||||
$_POST['userMail'] = 'john.doe@example.com';
|
||||
$_POST['urlImage'] = 'https://www.example.com/files/image_15.png';
|
||||
|
||||
ob_start();
|
||||
require 'abuse.php';
|
||||
ob_end_clean();
|
||||
|
||||
$imageBloquee = new ImageObject("15.png");
|
||||
$imageMemeMd5 = new ImageObject("16.png");
|
||||
$this->assertEquals(true, $imageBloquee->isSignalee(), "Image signalée doit l'être");
|
||||
$this->assertEquals(
|
||||
true,
|
||||
$imageBloquee = new ImageObject('image_15.png');
|
||||
$imageMemeMd5 = new ImageObject('image_16.png');
|
||||
|
||||
|
||||
$this->assertEmpty(
|
||||
$msgErreur,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message d\'erreur - Erreur : ' . $msgErreur
|
||||
);
|
||||
$this->assertTrue(
|
||||
$imageBloquee->isSignalee(),
|
||||
'Image signalée doit l\'être'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$imageMemeMd5->isSignalee(),
|
||||
"Image avec même MD5 qu'une image signalée doit l'être également"
|
||||
'Image avec même MD5 qu\'une image signalée doit l\'être également'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renvoi d'une image bloquée et demande de son affichage
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseRenvoiImage(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_POST['Submit'] = 1;
|
||||
$_SESSION['flag'] = true;
|
||||
$_FILES['fichier']['size'] = 146;
|
||||
$_FILES['fichier']['name'] = 'imageDejaBloquee.gif';
|
||||
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
|
||||
|
||||
ob_start();
|
||||
require 'upload.php';
|
||||
ob_end_clean();
|
||||
|
||||
$this->assertEmpty(
|
||||
$msgErreur,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message d\'erreur - Erreur : ' . $msgErreur
|
||||
);
|
||||
$this->assertEmpty(
|
||||
$msgWarning,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message de warning - Warning : ' . $msgWarning
|
||||
);
|
||||
$this->assertTrue(
|
||||
$monImage->isBloquee(),
|
||||
'Renvoi image déjà bloquée doit être isBloquée en BDD'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signalement d'une image approuvée
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseImageApprouvee(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_POST['Submit'] = 1;
|
||||
$_SESSION['flag'] = true;
|
||||
$_POST['userMail'] = 'john.doe@example.com';
|
||||
$_POST['urlImage'] = 'https://www.example.com/files/_image_404.png';
|
||||
|
||||
ob_start();
|
||||
require 'abuse.php';
|
||||
ob_end_clean();
|
||||
|
||||
$imageSignalee = new ImageObject('_image_404.png');
|
||||
$this->assertEmpty(
|
||||
$msgErreur,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message d\'erreur - Erreur : ' . $msgErreur
|
||||
);
|
||||
$this->assertFalse(
|
||||
$imageSignalee->isSignalee(),
|
||||
'Image approuvée qui est signalée ne doit pas être bloquée'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approbation d'une image signalée
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseImageSignaleePuisApprouvee(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
|
||||
// Flagguer l'image comme signalée
|
||||
$image = new ImageObject('_image_banned.png');
|
||||
$image->setSignalee(true);
|
||||
$image->sauver();
|
||||
|
||||
// Se connecter en tant que l'admin
|
||||
$monMembre = new UtilisateurObject();
|
||||
$monMembre->connexion('admin', 'password');
|
||||
|
||||
// Approuver l'image dans l'admin
|
||||
$_GET['approuver'] = '1';
|
||||
$_GET['idImage'] = '2';
|
||||
|
||||
ob_start();
|
||||
require 'admin/abuse.php';
|
||||
ob_end_clean();
|
||||
|
||||
$image = new ImageObject('_image_banned.png');
|
||||
$this->assertFalse(
|
||||
$image->isSignalee(),
|
||||
'Image signalée qui est approuvée ne doit plus être signalée'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renvoi d'une image déjà bloquée
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseImageRenvoiImageBloqueeDepuisReseauMalveillant(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$imagesAvantEnvoi = HelperAdmin::getImagesPotentiellementIndesirables();
|
||||
|
||||
$_SERVER['REMOTE_ADDR'] = '10.10.10.11';
|
||||
$_POST['Submit'] = 1;
|
||||
$_SESSION['flag'] = true;
|
||||
$_FILES['fichier']['size'] = 146;
|
||||
$_FILES['fichier']['name'] = 'imageDejaBloquee.gif';
|
||||
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
|
||||
|
||||
ob_start();
|
||||
require 'upload.php';
|
||||
ob_end_clean();
|
||||
|
||||
$imagesApresEnvoi = HelperAdmin::getImagesPotentiellementIndesirables();
|
||||
|
||||
$this->assertEmpty(
|
||||
$msgErreur,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message d\'erreur - Erreur : ' . $msgErreur
|
||||
);
|
||||
$this->assertEmpty(
|
||||
$msgWarning,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message de warning - Warning : ' . $msgWarning
|
||||
);
|
||||
$this->assertEquals(
|
||||
$imagesAvantEnvoi->count(),
|
||||
$imagesApresEnvoi->count(),
|
||||
'Le renvoi d\'une image bloquée doit être bloqué'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoi d'une image depuis le même réseau qu'une image bloquée
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseImageEnvoiDepuisReseauMalveillant(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$imagesAvantEnvoi = HelperAdmin::getImagesPotentiellementIndesirables();
|
||||
|
||||
$_SERVER['REMOTE_ADDR'] = '10.10.10.11';
|
||||
$_POST['Submit'] = 1;
|
||||
$_SESSION['flag'] = true;
|
||||
$_FILES['fichier']['size'] = 146;
|
||||
$_FILES['fichier']['name'] = 'rotation_original.gif';
|
||||
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
|
||||
|
||||
ob_start();
|
||||
require 'upload.php';
|
||||
ob_end_clean();
|
||||
|
||||
$imagesApresEnvoi = HelperAdmin::getImagesPotentiellementIndesirables();
|
||||
|
||||
$this->assertEmpty(
|
||||
$msgErreur,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message d\'erreur - Erreur : ' . $msgErreur
|
||||
);
|
||||
$this->assertEmpty(
|
||||
$msgWarning,
|
||||
__FUNCTION__ . ' ne devrait pas lever de message de warning - Warning : ' . $msgWarning
|
||||
);
|
||||
$this->assertEquals(
|
||||
($imagesAvantEnvoi->count() + 1),
|
||||
$imagesApresEnvoi->count(),
|
||||
'L\'image envoyée devrait être considérée comme potentiellement indésirable : ' . var_export($imagesApresEnvoi, true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image avec une miniature ENORMEMENT affichée
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseImageMiniatureTropAffichee(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$images = HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_);
|
||||
|
||||
$this->assertNotEmpty(
|
||||
$images,
|
||||
'Les affichages des miniatures doivent compter dans les affichages d\'une image pour la détection des abus : ' . var_export($images, true)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Division des seuils de détection pour une image envoyée du même réseau qu'une image déjà bloquée
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseDivisionSeuilDetectionSiReseauMalveillant(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
// Liste des images suspectes
|
||||
$listeImagesSuspectes = HelperAdmin::getImagesPotentiellementIndesirables();
|
||||
|
||||
$imagesTropAffichees = HelperAdmin::getImagesTropAffichees((_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_), true);
|
||||
|
||||
$this->assertContains(
|
||||
'image_20.gif',
|
||||
$listeImagesSuspectes,
|
||||
'L\'image 19 est suspecte car envoyée d\'un même réseau que l\'image 18'
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'image_20.gif',
|
||||
$imagesTropAffichees,
|
||||
'L\'image 19 a été trop affichée -> WARNING (elle est suspecte)'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Réputation des adresses IP basées sur les images déjà bloquées pour leur réseau
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseReputationIp(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
// Adresse IP ayant envoyé les fichiers bloqués
|
||||
$this->assertEquals(
|
||||
5,
|
||||
HelperAbuse::checkIpReputation('192.168.0.1'),
|
||||
'Le réseau 192.168.0.0/24 a 5 images bloquées'
|
||||
);
|
||||
// Adresse IP du même réseau que celle ayant envoyé les fichiers bloqués
|
||||
$this->assertEquals(
|
||||
5,
|
||||
HelperAbuse::checkIpReputation('192.168.0.100'),
|
||||
'Le réseau 192.168.0.0/24 a 5 images bloquées'
|
||||
);
|
||||
// Adresse IP random qui n'a pas d'images bloqués
|
||||
$this->assertEquals(
|
||||
0,
|
||||
HelperAbuse::checkIpReputation('2a01:ab51:8880:e010:1da5:be67:6a52:a5bf'),
|
||||
'Aucune image bloquée dans le réseau de cette adresse IP'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Projection du nombre d'affichage d'une image pour détecter une atteinte de limite ultérieure
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseProjectionAffichages(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$images = HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_, false, true);
|
||||
|
||||
$this->assertContains(
|
||||
'image_27.png',
|
||||
$images,
|
||||
'L\'image 27 doit être détectée comme dépassant le nombre d\'affichage en projection : ' . var_export($images, true)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Le blocage d'une image bloque toutes celles partageant le même MD5
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseContaminationMD5Blocage(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$monImage = new ImageObject('28', RessourceObject::SEARCH_BY_ID);
|
||||
$monImage->bloquer();
|
||||
|
||||
$image28 = new ImageObject('28', RessourceObject::SEARCH_BY_ID);
|
||||
$image29 = new ImageObject('29', RessourceObject::SEARCH_BY_ID);
|
||||
|
||||
$this->assertTrue(
|
||||
$image28->isBloquee(),
|
||||
'L\'image 28 doit être bloquée'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$image29->isBloquee(),
|
||||
'L\'image 29 doit être bloquée'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$image28->isApprouvee(),
|
||||
'L\'image 28 ne doit pas être approuvée'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$image29->isApprouvee(),
|
||||
'L\'image 29 ne doit pas être approuvée'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* L'approbation d'une image approuve toutes celles partageant le même MD5
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseContaminationMD5Approbation(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$monImage = new ImageObject('30', RessourceObject::SEARCH_BY_ID);
|
||||
$monImage->approuver();
|
||||
|
||||
$image30 = new ImageObject('30', RessourceObject::SEARCH_BY_ID);
|
||||
$image31 = new ImageObject('31', RessourceObject::SEARCH_BY_ID);
|
||||
$image32 = new ImageObject('32', RessourceObject::SEARCH_BY_ID);
|
||||
|
||||
$this->assertFalse(
|
||||
$image30->isBloquee(),
|
||||
'L\'image 30 ne doit pas être bloquée'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$image31->isBloquee(),
|
||||
'L\'image 31 ne doit pas être bloquée'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$image32->isBloquee(),
|
||||
'L\'image 32 ne doit pas être bloquée'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$image30->isSignalee(),
|
||||
'L\'image 30 ne doit pas être signalée'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$image31->isSignalee(),
|
||||
'L\'image 31 ne doit pas être signalée'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$image32->isSignalee(),
|
||||
'L\'image 32 ne doit pas être signalée'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$image30->isApprouvee(),
|
||||
'L\'image 30 doit être approuvée'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$image31->isApprouvee(),
|
||||
'L\'image 31 doit être approuvée'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$image32->isApprouvee(),
|
||||
'L\'image 32 doit être approuvée'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Une image demandée par un User-Agent suspect doit être signalée.
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testBlocageParUserAgent(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_SERVER['HTTP_USER_AGENT'] = 'someUserAgentNumberOne';
|
||||
$_SERVER['REQUEST_URI'] = 'files/image_33.png';
|
||||
|
||||
$monImage = new ImageObject('33', RessourceObject::SEARCH_BY_ID);
|
||||
$this->assertFalse(
|
||||
$monImage->isSignalee(),
|
||||
'L\'image ne doit pas être signalée de base.'
|
||||
);
|
||||
|
||||
ob_start();
|
||||
require 'displayPics.php';
|
||||
ob_end_clean();
|
||||
|
||||
$monImage = new ImageObject('33', RessourceObject::SEARCH_BY_ID);
|
||||
$this->assertTrue(
|
||||
$monImage->isSignalee(),
|
||||
'Signalement de l\'image basé sur le User-Agent présenté'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Projection du nombre d'affichage d'une image pour détecter une atteinte de limite ultérieure
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testAbuseNombreAffichagesAbusifs(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$images = HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_ABUSIF_, false, true, true);
|
||||
|
||||
$this->assertContains(
|
||||
'image_34.png',
|
||||
$images,
|
||||
'L\'image 34 doit être détectée comme ayant un nombre d\'affichages abusif : ' . var_export($images, true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,92 +21,119 @@
|
|||
|
||||
namespace ImageHebergTests;
|
||||
|
||||
use ImageHeberg\ImageObject;
|
||||
use ImageHeberg\MaBDD;
|
||||
use ImageHeberg\MetaObject;
|
||||
use ImageHeberg\MiniatureObject;
|
||||
use ImageHeberg\Outils;
|
||||
use ImageHeberg\RessourceInterface;
|
||||
use ImageHeberg\RessourceObject;
|
||||
use ImageHeberg\SessionObject;
|
||||
use ImageHeberg\UtilisateurObject;
|
||||
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class DisplayPicsTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* Affichage d'une image inexistante
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testImageInexistante()
|
||||
#[RunInSeparateProcess]
|
||||
public function testImageInexistante(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_SERVER['REQUEST_URI'] = 'files/fichierInexistant.jpg';
|
||||
|
||||
ob_start();
|
||||
require 'displayPics.php';
|
||||
ob_end_clean();
|
||||
|
||||
/* @var $monObjet RessourceObject */
|
||||
$this->assertEquals(_IMAGE_404_, $monObjet->getNomNouveau(), "image_404 si inexistante");
|
||||
$this->assertEquals(
|
||||
_IMAGE_404_,
|
||||
$monObjet->getNomNouveau(),
|
||||
'image_404 si inexistante'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affichage d'une image inexistante
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testMiniatureInexistante()
|
||||
#[RunInSeparateProcess]
|
||||
public function testMiniatureInexistante(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_SERVER['REQUEST_URI'] = 'files/thumbs/fichierInexistant.jpg';
|
||||
|
||||
ob_start();
|
||||
require 'displayPics.php';
|
||||
ob_end_clean();
|
||||
|
||||
/* @var $monObjet RessourceObject */
|
||||
$this->assertEquals(_IMAGE_404_, $monObjet->getNomNouveau(), "image_404 si inexistante");
|
||||
$this->assertEquals(
|
||||
_IMAGE_404_,
|
||||
$monObjet->getNomNouveau(),
|
||||
'image_404 si inexistante'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affichage d'une image inexistante
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testRepertoireInexistant()
|
||||
#[RunInSeparateProcess]
|
||||
public function testRepertoireInexistant(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_SERVER['REQUEST_URI'] = 'files/repertoireInexistant/fichierInexistant.jpg';
|
||||
|
||||
ob_start();
|
||||
require 'displayPics.php';
|
||||
ob_end_clean();
|
||||
|
||||
/* @var $monObjet RessourceObject */
|
||||
$this->assertEquals(_IMAGE_404_, $monObjet->getNomNouveau(), "image_404 si mauvais sous répertoire");
|
||||
$this->assertEquals(
|
||||
_IMAGE_404_,
|
||||
$monObjet->getNomNouveau(),
|
||||
'image_404 si mauvais sous répertoire'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affichage d'une image bloquée
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testImageBloquee()
|
||||
#[RunInSeparateProcess]
|
||||
public function testImageBloquee(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_SERVER['REQUEST_URI'] = 'files/imageBloquee.jpg';
|
||||
$_SERVER['REQUEST_URI'] = 'files/image_10.png';
|
||||
|
||||
ob_start();
|
||||
require 'displayPics.php';
|
||||
ob_end_clean();
|
||||
|
||||
/* @var $monObjet RessourceObject */
|
||||
$this->assertEquals(_IMAGE_BAN_, $monObjet->getNomNouveau(), "image_ban si image bloquée");
|
||||
$this->assertEquals(
|
||||
_IMAGE_BAN_,
|
||||
$monObjet->getNomNouveau(),
|
||||
'image_ban si image bloquée'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affichage d'une image signaléee
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testImageSignalee()
|
||||
#[RunInSeparateProcess]
|
||||
public function testImageSignalee(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||
$_SERVER['REQUEST_URI'] = 'files/imageSignalee.png';
|
||||
$_SERVER['REQUEST_URI'] = 'files/image_18.png';
|
||||
|
||||
ob_start();
|
||||
require 'displayPics.php';
|
||||
ob_end_clean();
|
||||
|
||||
/* @var $monObjet RessourceObject */
|
||||
$this->assertEquals(_IMAGE_BAN_, $monObjet->getNomNouveau(), "image_ban si image signalée");
|
||||
$this->assertEquals(
|
||||
_IMAGE_BAN_,
|
||||
$monObjet->getNomNouveau(),
|
||||
'image_ban si image signalée'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -22,209 +22,175 @@
|
|||
namespace ImageHebergTests;
|
||||
|
||||
use ImageHeberg\ImageObject;
|
||||
use ImageHeberg\MaBDD;
|
||||
use ImageHeberg\MetaObject;
|
||||
use ImageHeberg\MiniatureObject;
|
||||
use ImageHeberg\Outils;
|
||||
use ImageHeberg\RessourceInterface;
|
||||
use ImageHeberg\RessourceObject;
|
||||
use ImageHeberg\SessionObject;
|
||||
use ImageHeberg\UtilisateurObject;
|
||||
use ImagickException;
|
||||
use ImagickPixelException;
|
||||
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Imagick;
|
||||
|
||||
/**
|
||||
* L'entête des fichiers contient des informations sur la bibliothéque système les ayant produit
|
||||
* <CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 100
|
||||
*/
|
||||
class ImageObjectTest extends TestCase
|
||||
{
|
||||
// Rotation pour les images
|
||||
private const array ROTATION_ANGLES = [0, 90, 180, 270];
|
||||
// Couleurs des 4 coins : HG / BG / BD / HD
|
||||
private const array ROTATION_COULEURS = [
|
||||
0 => [
|
||||
'r' => 255,
|
||||
'g' => 0,
|
||||
'b' => 0,
|
||||
],
|
||||
1 => [
|
||||
'r' => 0,
|
||||
'g' => 255,
|
||||
'b' => 0,
|
||||
],
|
||||
2 => [
|
||||
'r' => 0,
|
||||
'g' => 0,
|
||||
'b' => 255,
|
||||
],
|
||||
3 => [
|
||||
'r' => 255,
|
||||
'g' => 255,
|
||||
'b' => 255,
|
||||
],
|
||||
];
|
||||
// Dimensions d'origine de l'image
|
||||
private const array ROTATION_DIM_ORIGINE = [640, 150];
|
||||
|
||||
/**
|
||||
* Rotation des images PNG
|
||||
* Les couleurs des images sont conservées à +/- 1 point de valeur
|
||||
* @param array $reference Couleur de référence
|
||||
* @param array $valeur Couleur à comparer
|
||||
* @return bool
|
||||
*/
|
||||
public function testRotationImagesPNG()
|
||||
private function compareColor(array $reference, array $valeur): bool
|
||||
{
|
||||
$monRetour = true;
|
||||
foreach ($reference as $key => $value) {
|
||||
if (
|
||||
$valeur[$key] !== $value
|
||||
&& $valeur[$key] !== ($value - 1)
|
||||
&& $valeur[$key] !== ($value + 1)
|
||||
) {
|
||||
$monRetour = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Debug
|
||||
if (!$monRetour) {
|
||||
echo PHP_EOL . 'Expected : ' . var_export($reference, true) . PHP_EOL . 'Actual : ' . var_export($valeur, true) . PHP_EOL;
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotation des images
|
||||
* @throws ImagickPixelException
|
||||
* @throws ImagickException
|
||||
*/
|
||||
#[RunInSeparateProcess]
|
||||
public function testRotationImages(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$monImage = new ImageObject();
|
||||
|
||||
$angle = 90;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.png',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '-a-partir-php-7.2.png',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle,
|
||||
"Rotation PNG " . $angle
|
||||
);
|
||||
foreach (_ACCEPTED_EXTENSIONS_ as $uneExtension) {
|
||||
foreach (self::ROTATION_ANGLES as $unAngle) {
|
||||
$monImage->rotation(
|
||||
$unAngle,
|
||||
_PATH_TESTS_IMAGES_ . 'rotation_original.' . $uneExtension,
|
||||
_PATH_TESTS_OUTPUT_ . 'rotation_original-' . $unAngle . '.' . $uneExtension
|
||||
);
|
||||
|
||||
$angle = 180;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.png',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '-jusqua-php-7.1.png',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle,
|
||||
"Rotation PNG " . $angle
|
||||
);
|
||||
// Calcul des dimensions théoriques
|
||||
$indiceLargeur = (($unAngle % 180) === 0 ? 0 : 1);
|
||||
$indiceHauteur = (($unAngle % 180) === 0 ? 1 : 0);
|
||||
|
||||
$angle = 270;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.png',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '-jusqua-php-7.1.png',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle,
|
||||
"Rotation PNG " . $angle
|
||||
);
|
||||
}
|
||||
// Vérifier les dimensions des images
|
||||
$imageInfo = getimagesize(_PATH_TESTS_OUTPUT_ . 'rotation_original-' . $unAngle . '.' . $uneExtension);
|
||||
$this->assertEquals(
|
||||
self::ROTATION_DIM_ORIGINE[$indiceLargeur],
|
||||
$imageInfo[0],
|
||||
'Largeur d\'image - Rotation ' . $uneExtension . ' ' . $unAngle
|
||||
);
|
||||
$this->assertEquals(
|
||||
self::ROTATION_DIM_ORIGINE[$indiceHauteur],
|
||||
$imageInfo[1],
|
||||
'Hauteur d\'image - Rotation ' . $uneExtension . ' ' . $unAngle
|
||||
);
|
||||
|
||||
/**
|
||||
* Rotation des images JPG
|
||||
* @depends testRotationImagesPNG
|
||||
*/
|
||||
public function testRotationImagesJPG()
|
||||
{
|
||||
$monImage = new ImageObject();
|
||||
|
||||
$angle = 90;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.jpg',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle
|
||||
);
|
||||
$monImage->rotation(
|
||||
0,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '-a-partir-php-7.2.jpg',
|
||||
_PATH_TESTS_OUTPUT_ . 'ATTENDU_image_banned.jpg-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_OUTPUT_ . 'ATTENDU_image_banned.jpg-' . $angle,
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle,
|
||||
"Rotation JPG " . $angle
|
||||
);
|
||||
|
||||
$angle = 180;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.jpg',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '-jusqua-php-7.1.jpg',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle,
|
||||
"Rotation JPG " . $angle
|
||||
);
|
||||
|
||||
$angle = 270;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.jpg',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '-jusqua-php-7.1.jpg',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle,
|
||||
"Rotation JPG " . $angle
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotation des images GIF
|
||||
* Pas de changement en fonction des versions de PHP
|
||||
* @depends testRotationImagesJPG
|
||||
*/
|
||||
public function testRotationImagesGIF()
|
||||
{
|
||||
$monImage = new ImageObject();
|
||||
|
||||
$angle = 90;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.gif',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '.gif',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle,
|
||||
"Rotation GIF " . $angle
|
||||
);
|
||||
$angle = 180;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.gif',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '.gif',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle,
|
||||
"Rotation GIF " . $angle
|
||||
);
|
||||
$angle = 270;
|
||||
$monImage->rotation(
|
||||
$angle,
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned.gif',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_banned-' . $angle . '.gif',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle,
|
||||
"Rotation GIF " . $angle
|
||||
);
|
||||
// Vérifier les couleurs
|
||||
$image = new Imagick(_PATH_TESTS_OUTPUT_ . 'rotation_original-' . $unAngle . '.' . $uneExtension);
|
||||
$this->assertTrue(
|
||||
$this->compareColor(self::ROTATION_COULEURS[round($unAngle / 90)], $image->getImagePixelColor(0, 0)->getColor()),
|
||||
'Pixel (0,0) - Couleur ' . $uneExtension . ' - Rotation ' . $unAngle
|
||||
);
|
||||
$this->assertEquals(
|
||||
$this->compareColor(self::ROTATION_COULEURS[(round($unAngle / 90) + 1) % 4], $image->getImagePixelColor(0, self::ROTATION_DIM_ORIGINE[$indiceHauteur])->getColor()),
|
||||
'Pixel (0,' . self::ROTATION_DIM_ORIGINE[$indiceHauteur] . ') - Couleur ' . $uneExtension . ' - Rotation ' . $unAngle
|
||||
);
|
||||
$this->assertEquals(
|
||||
$this->compareColor(self::ROTATION_COULEURS[(round($unAngle / 90) + 2) % 4], $image->getImagePixelColor(self::ROTATION_DIM_ORIGINE[$indiceLargeur], self::ROTATION_DIM_ORIGINE[$indiceHauteur])->getColor()),
|
||||
'Pixel (' . self::ROTATION_DIM_ORIGINE[$indiceLargeur] . ',' . self::ROTATION_DIM_ORIGINE[$indiceHauteur] . ') - Couleur ' . $uneExtension . ' - Rotation ' . $unAngle
|
||||
);
|
||||
$this->assertEquals(
|
||||
$this->compareColor(self::ROTATION_COULEURS[(round($unAngle / 90) + 3) % 4], $image->getImagePixelColor(self::ROTATION_DIM_ORIGINE[$indiceLargeur], 0)->getColor()),
|
||||
'Pixel (' . self::ROTATION_DIM_ORIGINE[$indiceLargeur] . ',0) - Couleur ' . $uneExtension . ' - Rotation ' . $unAngle
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redimensionnement des images
|
||||
* @depends testRotationImagesGIF
|
||||
*/
|
||||
public function testRedimensionnementImages()
|
||||
#[RunInSeparateProcess]
|
||||
public function testRedimensionnementImages(): void
|
||||
{
|
||||
require 'config/config.php';
|
||||
$monImage = new ImageObject();
|
||||
|
||||
/*
|
||||
* Cas null
|
||||
* Cas incohérents => Ne rien faire
|
||||
*/
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 800),
|
||||
"Pas d'agrandissement"
|
||||
'Pas d\'agrandissement'
|
||||
);
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 601, 800),
|
||||
"Pas d'agrandissement"
|
||||
'Pas d\'agrandissement'
|
||||
);
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 801),
|
||||
"Pas d'agrandissement"
|
||||
'Pas d\'agrandissement'
|
||||
);
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 599, 800),
|
||||
"Pas d'agrandissement"
|
||||
'Pas d\'agrandissement'
|
||||
);
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 799),
|
||||
"Pas d'agrandissement"
|
||||
'Pas d\'agrandissement'
|
||||
);
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 0, 799),
|
||||
"Image de taille zéro"
|
||||
'Image de taille zéro'
|
||||
);
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 0, 0),
|
||||
"Image de taille zéro"
|
||||
'Image de taille zéro'
|
||||
);
|
||||
$this->assertEquals(
|
||||
null,
|
||||
$this->assertFalse(
|
||||
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 10, 0),
|
||||
"Image de taille zéro"
|
||||
'Image de taille zéro'
|
||||
);
|
||||
|
||||
/*
|
||||
|
@ -237,10 +203,16 @@ class ImageObjectTest extends TestCase
|
|||
200,
|
||||
400
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_portrait_200x400.png-a-partir-php-7.2',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_portrait_200x400.png',
|
||||
"Redimensionnement portrait 200x400"
|
||||
$imageInfo = getimagesize(_PATH_TESTS_OUTPUT_ . 'image_portrait_200x400.png');
|
||||
$this->assertEquals(
|
||||
200,
|
||||
$imageInfo[0],
|
||||
'Redimensionnement 600x800 -> 200x400'
|
||||
);
|
||||
$this->assertEquals(
|
||||
267,
|
||||
$imageInfo[1],
|
||||
'Redimensionnement 600x800 -> 200x400'
|
||||
);
|
||||
|
||||
// Doit être 150x200
|
||||
|
@ -250,10 +222,16 @@ class ImageObjectTest extends TestCase
|
|||
400,
|
||||
200
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_portrait_400x200.png-a-partir-php-7.2',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_portrait_400x200.png',
|
||||
"Redimensionnement portrait 400x200"
|
||||
$imageInfo = getimagesize(_PATH_TESTS_OUTPUT_ . 'image_portrait_400x200.png');
|
||||
$this->assertEquals(
|
||||
150,
|
||||
$imageInfo[0],
|
||||
'Redimensionnement 600x800 -> 400x200'
|
||||
);
|
||||
$this->assertEquals(
|
||||
200,
|
||||
$imageInfo[1],
|
||||
'Redimensionnement 600x800 -> 400x200'
|
||||
);
|
||||
|
||||
/*
|
||||
|
@ -266,10 +244,16 @@ class ImageObjectTest extends TestCase
|
|||
400,
|
||||
200
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_paysage_400x200.png-a-partir-php-7.2',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_paysage_400x200.png',
|
||||
"Redimensionnement paysage 400x200"
|
||||
$imageInfo = getimagesize(_PATH_TESTS_OUTPUT_ . 'image_paysage_400x200.png');
|
||||
$this->assertEquals(
|
||||
267,
|
||||
$imageInfo[0],
|
||||
'Redimensionnement 800x600 -> 400x200'
|
||||
);
|
||||
$this->assertEquals(
|
||||
200,
|
||||
$imageInfo[1],
|
||||
'Redimensionnement 800x600 -> 400x200'
|
||||
);
|
||||
|
||||
// Doit être 200x150
|
||||
|
@ -279,10 +263,16 @@ class ImageObjectTest extends TestCase
|
|||
200,
|
||||
400
|
||||
);
|
||||
$this->assertFileEquals(
|
||||
_PATH_TESTS_IMAGES_ . 'image_paysage_200x400.png-a-partir-php-7.2',
|
||||
_PATH_TESTS_OUTPUT_ . 'image_paysage_200x400.png',
|
||||
"Redimensionnement paysage 200x400"
|
||||
$imageInfo = getimagesize(_PATH_TESTS_OUTPUT_ . 'image_paysage_200x400.png');
|
||||
$this->assertEquals(
|
||||
200,
|
||||
$imageInfo[0],
|
||||
'Redimensionnement 800x600 -> 200x400'
|
||||
);
|
||||
$this->assertEquals(
|
||||
150,
|
||||
$imageInfo[1],
|
||||
'Redimensionnement 800x600 -> 200x400'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,26 +21,16 @@
|
|||
|
||||
namespace ImageHebergTests;
|
||||
|
||||
use ImageHeberg\ImageObject;
|
||||
use ImageHeberg\MaBDD;
|
||||
use ImageHeberg\MetaObject;
|
||||
use ImageHeberg\MiniatureObject;
|
||||
use ImageHeberg\Outils;
|
||||
use ImageHeberg\RessourceInterface;
|
||||
use ImageHeberg\RessourceObject;
|
||||
use ImageHeberg\SessionObject;
|
||||
use ImageHeberg\UtilisateurObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class InstallationTest extends TestCase
|
||||
{
|
||||
|
||||
public function testValidationInstallation()
|
||||
public function testValidationInstallation(): void
|
||||
{
|
||||
/**
|
||||
* Valeur attendue
|
||||
*/
|
||||
$this->expectOutputString("L'installation est OK !");
|
||||
$this->expectOutputRegex('#.*L\'installation est OK !$#U');
|
||||
|
||||
/**
|
||||
* Exécution du script...
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,25 +21,19 @@
|
|||
|
||||
namespace ImageHebergTests;
|
||||
|
||||
use ImageHeberg\ImageObject;
|
||||
use ImageHeberg\MaBDD;
|
||||
use ImageHeberg\MetaObject;
|
||||
use ImageHeberg\MiniatureObject;
|
||||
use ImageHeberg\Outils;
|
||||
use ImageHeberg\RessourceInterface;
|
||||
use ImageHeberg\RessourceObject;
|
||||
use ImageHeberg\SessionObject;
|
||||
use ImageHeberg\UtilisateurObject;
|
||||
use PDO;
|
||||
use PHPUnit\Framework\Attributes\Depends;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MembreTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* Fonction requise par l'extension Database
|
||||
* @return type
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConnection()
|
||||
public function getConnection(): mixed
|
||||
{
|
||||
$pdo = new PDO('sqlite::memory:');
|
||||
return $this->createDefaultDBConnection($pdo, ':memory:');
|
||||
|
@ -47,14 +41,14 @@ class MembreTest extends TestCase
|
|||
|
||||
/**
|
||||
* Fonction requise par l'extension Database
|
||||
* @return \PHPUnit_Extensions_Database_DataSet_DefaultDataSet
|
||||
* @return PHPUnit_Extensions_Database_DataSet_DefaultDataSet
|
||||
*/
|
||||
public function getDataSet()
|
||||
public function getDataSet(): PHPUnit_Extensions_Database_DataSet_DefaultDataSet
|
||||
{
|
||||
return new PHPUnit_Extensions_Database_DataSet_DefaultDataSet();
|
||||
}
|
||||
|
||||
public function testConnexionMembreExistant()
|
||||
public function testConnexionMembreExistant(): void
|
||||
{
|
||||
// Chargement de la configuration
|
||||
require_once 'config/config.php';
|
||||
|
@ -78,14 +72,18 @@ class MembreTest extends TestCase
|
|||
* Vérification des valeurs
|
||||
*/
|
||||
$maSession = new SessionObject();
|
||||
$this->assertEquals(UtilisateurObject::LEVEL_ADMIN, $maSession->getLevel(), "connexion : doit être OK");
|
||||
$this->assertEquals(
|
||||
UtilisateurObject::LEVEL_ADMIN,
|
||||
$maSession->getLevel(),
|
||||
'connexion : doit être OK'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Création d'un compte membre avec un nom déjà existant
|
||||
* @depends testConnexionMembreExistant
|
||||
*/
|
||||
public function testMembreCreerCompteDoublon()
|
||||
#[Depends('testConnexionMembreExistant')]
|
||||
public function testMembreCreerCompteDoublon(): void
|
||||
{
|
||||
unset($_POST);
|
||||
/**
|
||||
|
@ -109,18 +107,17 @@ class MembreTest extends TestCase
|
|||
* Vérification des valeurs
|
||||
*/
|
||||
$monMembre = new UtilisateurObject();
|
||||
$this->assertEquals(
|
||||
false,
|
||||
$this->assertFalse(
|
||||
$monMembre->connexion($_POST['userName'], $_POST['userPassword']),
|
||||
"connexion : le nom d'utilisateur doit être unique"
|
||||
'connexion : le nom d\'utilisateur doit être unique'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Création d'un compte membre.
|
||||
* @depends testMembreCreerCompteDoublon
|
||||
*/
|
||||
public function testMembreCreerCompte()
|
||||
#[Depends('testMembreCreerCompteDoublon')]
|
||||
public function testMembreCreerCompte(): void
|
||||
{
|
||||
unset($_POST);
|
||||
/**
|
||||
|
@ -149,23 +146,41 @@ class MembreTest extends TestCase
|
|||
* Vérification des valeurs
|
||||
*/
|
||||
// Email
|
||||
$this->assertEquals('myMail@example.com', $monMembre->getEmail(), "Vérification email");
|
||||
$this->assertEquals(
|
||||
'mymail@example.com',
|
||||
$monMembre->getEmail(),
|
||||
'Vérification email'
|
||||
);
|
||||
// ID
|
||||
$this->assertEquals(3, $monMembre->getId());
|
||||
$this->assertEquals(
|
||||
3,
|
||||
$monMembre->getId()
|
||||
);
|
||||
// @ IP d'inscription
|
||||
$this->assertEquals('127.0.0.1', $monMembre->getIpInscription());
|
||||
$this->assertEquals(
|
||||
'127.0.0.1',
|
||||
$monMembre->getIpInscription()
|
||||
);
|
||||
// Niveau de droits
|
||||
$this->assertEquals(UtilisateurObject::LEVEL_USER, $monMembre->getLevel());
|
||||
$this->assertEquals(
|
||||
UtilisateurObject::LEVEL_USER,
|
||||
$monMembre->getLevel()
|
||||
);
|
||||
// Nom
|
||||
$this->assertEquals('username', $monMembre->getUserName());
|
||||
$this->assertEquals(true, $monMembre->connexion($_POST['userName'], $_POST['userPassword']));
|
||||
$this->assertEquals(
|
||||
'username',
|
||||
$monMembre->getUserName()
|
||||
);
|
||||
$this->assertTrue(
|
||||
$monMembre->connexion($_POST['userName'], $_POST['userPassword'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modification du mail
|
||||
* @depends testMembreCreerCompte
|
||||
*/
|
||||
public function testMembreModifierMail()
|
||||
#[Depends('testMembreCreerCompte')]
|
||||
public function testMembreModifierMail(): void
|
||||
{
|
||||
unset($_POST);
|
||||
/**
|
||||
|
@ -180,7 +195,10 @@ class MembreTest extends TestCase
|
|||
* Simulation d'une connexion
|
||||
*/
|
||||
$unMembre = new UtilisateurObject();
|
||||
$this->assertEquals(true, $unMembre->connexion('username', $_POST['userPasswordMail']), "connexion avant");
|
||||
$this->assertTrue(
|
||||
$unMembre->connexion('username', $_POST['userPasswordMail']),
|
||||
'connexion avant'
|
||||
);
|
||||
|
||||
/**
|
||||
* Appel de la page
|
||||
|
@ -198,15 +216,22 @@ class MembreTest extends TestCase
|
|||
* Vérification des valeurs
|
||||
*/
|
||||
// Email
|
||||
$this->assertEquals('john.doe@example.com', $monMembre->getEmail(), "getEmail");
|
||||
$this->assertEquals(true, $monMembre->connexion('username', $_POST['userPasswordMail']), "connexion après");
|
||||
$this->assertEquals(
|
||||
'john.doe@example.com',
|
||||
$monMembre->getEmail(),
|
||||
'getEmail'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$monMembre->connexion('username', $_POST['userPasswordMail']),
|
||||
'connexion après'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modification du mot de passe
|
||||
* @depends testMembreModifierMail
|
||||
*/
|
||||
public function testMembreModifierPassword()
|
||||
#[Depends('testMembreModifierMail')]
|
||||
public function testMembreModifierPassword(): void
|
||||
{
|
||||
unset($_POST);
|
||||
/**
|
||||
|
@ -221,7 +246,10 @@ class MembreTest extends TestCase
|
|||
* Simulation d'une connexion
|
||||
*/
|
||||
$unMembre = new UtilisateurObject();
|
||||
$this->assertEquals(true, $unMembre->connexion('username', $_POST['oldUserPassword']), "connexion avant");
|
||||
$this->assertTrue(
|
||||
$unMembre->connexion('username', $_POST['oldUserPassword']),
|
||||
'connexion avant'
|
||||
);
|
||||
|
||||
/**
|
||||
* Appel de la page
|
||||
|
@ -238,15 +266,21 @@ class MembreTest extends TestCase
|
|||
/**
|
||||
* Vérification des valeurs
|
||||
*/
|
||||
$this->assertEquals(true, $monMembre->connexion('username', $_POST['newUserPassword']), "connexion");
|
||||
$this->assertEquals(false, $monMembre->connexion('username', $_POST['oldUserPassword']), "connexion");
|
||||
$this->assertTrue(
|
||||
$monMembre->connexion('username', $_POST['newUserPassword']),
|
||||
'connexion'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$monMembre->connexion('username', $_POST['oldUserPassword']),
|
||||
'connexion'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression du compte sans cochage de la checkbox
|
||||
* @depends testMembreModifierPassword
|
||||
*/
|
||||
public function testMembreSupprimerCompteRequiertCheckbox()
|
||||
#[Depends('testMembreModifierPassword')]
|
||||
public function testMembreSupprimerCompteRequiertCheckbox(): void
|
||||
{
|
||||
unset($_POST);
|
||||
/**
|
||||
|
@ -260,7 +294,10 @@ class MembreTest extends TestCase
|
|||
* Simulation d'une connexion
|
||||
*/
|
||||
$unMembre = new UtilisateurObject();
|
||||
$this->assertEquals(true, $unMembre->connexion('username', $_POST['userPasswordDelete']), "connexion avant");
|
||||
$this->assertTrue(
|
||||
$unMembre->connexion('username', $_POST['userPasswordDelete']),
|
||||
'connexion avant'
|
||||
);
|
||||
|
||||
/**
|
||||
* Appel de la page
|
||||
|
@ -277,18 +314,17 @@ class MembreTest extends TestCase
|
|||
/**
|
||||
* Vérification des valeurs
|
||||
*/
|
||||
$this->assertEquals(
|
||||
true,
|
||||
$this->assertTrue(
|
||||
$monMembre->connexion('username', $_POST['userPasswordDelete']),
|
||||
"connexion devrait être possible"
|
||||
'connexion devrait être possible'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression du compte
|
||||
* @depends testMembreSupprimerCompteRequiertCheckbox
|
||||
*/
|
||||
public function testMembreSupprimerCompte()
|
||||
#[Depends('testMembreSupprimerCompteRequiertCheckbox')]
|
||||
public function testMembreSupprimerCompte(): void
|
||||
{
|
||||
unset($_POST);
|
||||
/**
|
||||
|
@ -303,7 +339,10 @@ class MembreTest extends TestCase
|
|||
* Simulation d'une connexion
|
||||
*/
|
||||
$unMembre = new UtilisateurObject();
|
||||
$this->assertEquals(true, $unMembre->connexion('username', $_POST['userPasswordDelete']), "connexion avant");
|
||||
$this->assertTrue(
|
||||
$unMembre->connexion('username', $_POST['userPasswordDelete']),
|
||||
'connexion avant'
|
||||
);
|
||||
|
||||
/**
|
||||
* Appel de la page
|
||||
|
@ -320,18 +359,17 @@ class MembreTest extends TestCase
|
|||
/**
|
||||
* Vérification des valeurs
|
||||
*/
|
||||
$this->assertEquals(
|
||||
false,
|
||||
$this->assertFalse(
|
||||
$monMembre->connexion('username', $_POST['userPasswordDelete']),
|
||||
"connexion ne devrait plus être possible"
|
||||
'connexion ne devrait plus être possible'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connexion au compte créé lors de la création de la BDD
|
||||
* @depends testMembreSupprimerCompte
|
||||
*/
|
||||
public function testConnexionCompteHistorique()
|
||||
#[Depends('testMembreSupprimerCompte')]
|
||||
public function testConnexionCompteHistorique(): void
|
||||
{
|
||||
unset($_POST);
|
||||
/**
|
||||
|
@ -346,10 +384,9 @@ class MembreTest extends TestCase
|
|||
/**
|
||||
* Vérification des valeurs
|
||||
*/
|
||||
$this->assertEquals(
|
||||
true,
|
||||
$this->assertTrue(
|
||||
$monMembre->connexion('admin', 'password'),
|
||||
"connexion au compte créé à l'import de la BDD devrait être possible"
|
||||
'connexion au compte créé à l\'import de la BDD devrait être possible'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
98
__tests/_bootstrap.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Préconfiguration de l'environnement de tests
|
||||
* - Calcul des MD5 des images locales (dépendant de la version de PHP)
|
||||
* - Mise à jour en BDD des MD5 enregistrés
|
||||
* - Copie des fichiers requis
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHebergTests;
|
||||
|
||||
use ImageHeberg\HelperImage;
|
||||
use ImageHeberg\MaBDD;
|
||||
|
||||
require 'config/config.php';
|
||||
|
||||
// Faire la liste des fichiers
|
||||
$tabFiles = [];
|
||||
foreach (scandir(_PATH_TESTS_IMAGES_A_IMPORTER_) as $file) {
|
||||
if (is_file(_PATH_TESTS_IMAGES_A_IMPORTER_ . $file)) {
|
||||
if (
|
||||
in_array(HelperImage::getExtension(_PATH_TESTS_IMAGES_A_IMPORTER_ . $file), _ACCEPTED_EXTENSIONS_, true)
|
||||
&& HelperImage::isModifiableEnMemoire(_PATH_TESTS_IMAGES_A_IMPORTER_ . $file)
|
||||
) {
|
||||
$tabFiles[$file] = _PATH_TESTS_IMAGES_A_IMPORTER_ . $file;
|
||||
}
|
||||
// Remettre à disposition le fichier pour les tests
|
||||
copy(_PATH_TESTS_IMAGES_A_IMPORTER_ . $file, _PATH_TESTS_IMAGES_ . $file);
|
||||
}
|
||||
}
|
||||
|
||||
// Optimiser localement chaque image et en calculer le MD5 résultant
|
||||
foreach ($tabFiles as $file => $path) {
|
||||
// Créer un fichier temporaire pour travailler dessus
|
||||
$fileTmp = tempnam('/tmp/', 'ih');
|
||||
|
||||
// PHP ne gère pas les images WebP animée -> ne pas faire de traitements
|
||||
if (!HelperImage::isAnimatedWebp($path)) {
|
||||
// Optimiser l'image (permettra de comparer son hash avec celles déjà stockées)
|
||||
HelperImage::setImage(HelperImage::getImage($path), HelperImage::getType($path), $fileTmp);
|
||||
} else {
|
||||
copy($path, $fileTmp);
|
||||
}
|
||||
|
||||
// Calculer le MD5 de l'image
|
||||
$md5 = md5_file($fileTmp);
|
||||
|
||||
// Corriger l'information en BDD
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE images SET md5 = :md5 WHERE old_name = :oldName');
|
||||
$req->bindValue(':md5', $md5);
|
||||
$req->bindValue(':oldName', $file);
|
||||
$req->execute();
|
||||
|
||||
// Copier le fichier dans le bon répertoire
|
||||
$fileDst = _PATH_IMAGES_ . substr($md5, 0, 1) . '/' . $md5;
|
||||
copy($fileTmp, $fileDst);
|
||||
echo $file . ' -> ' . $fileDst . PHP_EOL;
|
||||
}
|
||||
|
||||
// Traitement pour ImageUploadAndDeleteTest::testSuppressionImagePlusieursMiniatures()
|
||||
$tabThumbs = [
|
||||
'image_a_supprimerMultiple-100x100.png' => _PATH_TESTS_IMAGES_ . 'image_a_supprimerMultiple-100x100.png',
|
||||
'image_a_supprimerMultiple-200x200.png' => _PATH_TESTS_IMAGES_ . 'image_a_supprimerMultiple-200x200.png',
|
||||
];
|
||||
foreach ($tabThumbs as $file => $path) {
|
||||
// Calculer le MD5 de l'image
|
||||
$md5 = md5_file($path);
|
||||
|
||||
// Corriger l'information en BDD
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE thumbnails SET md5 = :md5 WHERE new_name = :newName');
|
||||
$req->bindValue(':md5', $md5);
|
||||
$req->bindValue(':newName', $file);
|
||||
$req->execute();
|
||||
|
||||
// Copier le fichier dans le bon répertoire
|
||||
$fileDst = _PATH_MINIATURES_ . substr($md5, 0, 1) . '/' . $md5;
|
||||
copy($path, $fileDst);
|
||||
echo $file . ' -> ' . $fileDst . PHP_EOL;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
10
|
|
@ -1 +0,0 @@
|
|||
4
|
|
@ -1 +0,0 @@
|
|||
2
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,50 +24,70 @@
|
|||
*/
|
||||
/* Base de données */
|
||||
// Serveur de base de données
|
||||
define('_BDD_HOST_', 'localhost');
|
||||
const _BDD_HOST_ = 'localhost';
|
||||
// Utilisateur SQL
|
||||
define('_BDD_USER_', 'root');
|
||||
const _BDD_USER_ = 'root';
|
||||
// Mot de passe SQL
|
||||
define('_BDD_PASS_', 'root');
|
||||
const _BDD_PASS_ = 'root';
|
||||
// Nom de la base de données
|
||||
define('_BDD_NAME_', 'imageheberg');
|
||||
const _BDD_NAME_ = 'imageheberg';
|
||||
|
||||
|
||||
/* Système de fichiers */
|
||||
// Emplacement de votre site sur le système de fichiers de votre hébergeur
|
||||
define('_PATH_', '/home/runner/work/image-heberg.fr/image-heberg.fr/');
|
||||
const _PATH_ = '/home/runner/work/image-heberg.fr/image-heberg.fr/';
|
||||
|
||||
|
||||
/* A propos de l'outil */
|
||||
// Nom affiché du service
|
||||
define('_SITE_NAME_', 'monSite');
|
||||
const _SITE_NAME_ = 'monSite';
|
||||
// URL du site
|
||||
define('_BASE_URL_', 'www.example.com/');
|
||||
const _BASE_URL_ = 'www.example.com/';
|
||||
// Administrateur du site
|
||||
define('_ADMINISTRATEUR_NOM_', 'John DOE');
|
||||
const _ADMINISTRATEUR_NOM_ = 'John DOE';
|
||||
// Site web de l'administrateur
|
||||
define('_ADMINISTRATEUR_SITE_', '//www.example.com/');
|
||||
const _ADMINISTRATEUR_SITE_ = '//www.example.com/';
|
||||
// Mail de l'administrateur (non affiché)
|
||||
define('_ADMINISTRATEUR_EMAIL_', 'john.doe@example.com');
|
||||
const _ADMINISTRATEUR_EMAIL_ = 'john.doe@example.com';
|
||||
|
||||
|
||||
/* Informations légales */
|
||||
// Hébergeur du site
|
||||
define('_HEBERGEUR_NOM_', 'OVH');
|
||||
const _HEBERGEUR_NOM_ = 'OVH';
|
||||
// Site web de l'hébergeur
|
||||
define('_HEBERGEUR_SITE_', '//www.ovh.com');
|
||||
const _HEBERGEUR_SITE_ = '//www.ovh.com';
|
||||
|
||||
|
||||
/* Configurations spécifiques de l'outil */
|
||||
// Poids maximal des fichiers
|
||||
define('_IMAGE_POIDS_MAX_', 5242880);
|
||||
const _IMAGE_POIDS_MAX_ = 5242880;
|
||||
// Délai de conservation d'une image jamais affichée (en jours)
|
||||
define('_DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_', 7);
|
||||
const _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ = 7;
|
||||
// Délai depuis le dernier affichage d'une image avant de la supprimer (en jours)
|
||||
define('_DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_', 365);
|
||||
const _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ = 365;
|
||||
// Volume maximal de stockage d'images (en Go)
|
||||
define('_QUOTA_MAXIMAL_IMAGES_GO_', 90);
|
||||
const _QUOTA_MAXIMAL_IMAGES_GO_ = 90;
|
||||
// Affichage des messages d'erreur
|
||||
define('_DEBUG_', true);
|
||||
const _DEBUG_ = true;
|
||||
|
||||
|
||||
/* Gestion des abus */
|
||||
// Nombre d'affichages par jour à partir duquel une image est suspecte
|
||||
const _ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ = 1500;
|
||||
// Nombre d'affichages par jour à partir duquel une image est automatiquement bloquée
|
||||
const _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ = 100000;
|
||||
// Nombre d'affichages par jour à partir duquel une image est clairement abusive;
|
||||
const _ABUSE_NB_AFFICHAGES_PAR_JOUR_ABUSIF_ = 10 * _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_;
|
||||
// Division des seuils d'abus si une image est considérée comme suspecte
|
||||
const _ABUSE_DIVISION_SEUILS_SI_SUSPECT_ = 2;
|
||||
|
||||
// Désactiver l'envoi d'images depuis un noeud de sortie Tor
|
||||
const _TOR_DISABLE_UPLOAD_ = true;
|
||||
// Désactiver l'envoi d'images au bout de x images bloquées (mettre 0 pour ne pas l'activer)
|
||||
const _ABUSE_DISABLE_UPLOAD_AFTER_X_IMAGES_ = 5;
|
||||
|
||||
// User-Agent pour lesquels bloquer les images
|
||||
const _ABUSE_DISABLE_PICS_WHEN_USERE_AGENT_ = ['someUserAgentNumberOne', 'AnoterUserAgentNumberTwo'];
|
||||
|
||||
/**
|
||||
* FIN DES CHAMPS A CONFIGURER
|
||||
|
@ -77,11 +97,11 @@ define('_DEBUG_', true);
|
|||
*/
|
||||
// Salt pour les mots de passe
|
||||
// Legacy - n'est plus requis !!
|
||||
define('_GRAIN_DE_SEL_', '');
|
||||
const _GRAIN_DE_SEL_ = '';
|
||||
/**
|
||||
* FIN DES CHAMPS A COMPLETER UNIQUEMENT SI VOUS AVEZ UNE VERSION ANTERIEURE A v2.0.4
|
||||
*/
|
||||
// Activation des tests Tests TRAVIS-CI
|
||||
define('_PHPUNIT_', true);
|
||||
const _PHPUNIT_ = true;
|
||||
|
||||
require _PATH_ . 'config/image-heberg.php';
|
||||
|
|
102
__tests/data.sql
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -19,43 +19,109 @@
|
|||
--
|
||||
-- Image bloquée
|
||||
--
|
||||
INSERT INTO `images` (`id`, `ip_envoi`, `date_envoi`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`) VALUES
|
||||
(10, '127.0.0.1', '2008-01-01 00:00:00', 'imageBloquee.jpg', 'imageBloquee.jpg', 10, 10, 10, NULL, 0, 0, '6858ce6ddc171a0fd9640831a5e74dfd', 1, 0);
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(10, '127.0.0.1', '2008-01-01 00:00:00', 'image_a_supprimer.png', 'image_10.png', 10, 10, 10, '0000-00-00', 0, 0, 'to-be-calculatedto-be-calculated', 1, 0, 0, '127.0.2');
|
||||
|
||||
--
|
||||
-- Images à supprimer
|
||||
--
|
||||
INSERT INTO `images` (`id`, `ip_envoi`, `date_envoi`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`) VALUES
|
||||
(11, '127.0.0.1', '2008-01-01 00:00:00', 'image_a_supprimer.png', '100000019001334055750.png', 4239, 400, 640, NULL, 0, 0, 'e656d1b6582a15f0f458006898b40e29', 0, 0),
|
||||
(12, '127.0.0.10', NOW(), 'image_a_supprimer.png', '147834019001334055750.png', 4239, 400, 640, NULL, 0, 0, 'e656d1b6582a15f0f458006898b40e29', 0, 0),
|
||||
(13, '127.0.0.1', '2016-01-01 00:00:00', 'image.png', '146734019451334055750.png', 4239, 400, 640, NULL, 0, 0, 'a876d1b6582a15f0f458006898b40e29', 0, 0),
|
||||
(14, '127.0.0.1', '2016-01-01 00:00:00', 'image_a_supprimerMultiple.png', '14777777.png', 4239, 400, 640, NULL, 0, 0, 'aec65c6b4469bb7267d2d55af5fbd87b', 0, 0),
|
||||
(15, '127.0.0.1', '2016-01-01 00:00:00', 'imageQuiSeraBloquee.png', '15.png', 4239, 400, 640, NULL, 0, 0, 'bec65c6b4469bb7267d2d55af5fbd87b', 0, 0),
|
||||
(16, '127.0.0.1', '2016-01-01 00:00:00', 'imageAvecMemeMd5QuiDoitEtreBloquee.png', '16.png', 4239, 400, 640, NULL, 0, 0, 'bec65c6b4469bb7267d2d55af5fbd87b', 0, 0);
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(11, '127.0.0.1', '2008-01-01 00:00:00', 'image_a_supprimer.png', 'image_11.png', 4239, 400, 640, '0000-00-00', 0, 0, 'to-be-calculatedto-be-calculated', 0, 0, 0, '127.0.0'),
|
||||
(12, '127.0.0.10', NOW(), 'image_portrait_600x800.png', 'image_12.png', 4239, 400, 640, '0000-00-00', 0, 0, 'to-be-calculatedto-be-calculated', 0, 0, 0, '127.0.0'),
|
||||
(13, '127.0.0.10', NOW(), 'imageBleue10.png', 'image_13.png', 4239, 400, 640, '0000-00-00', 0, 0, 'to-be-calculatedto-be-calculated', 0, 0, 0, '127.0.0'),
|
||||
(14, '127.0.0.1', '2016-01-01 00:00:00', 'image_a_supprimerMultiple.png', 'image_14.png', 4239, 400, 640, '0000-00-00', 0, 0, 'to-be-calculatedto-be-calculated', 0, 0, 0, '127.0.0'),
|
||||
(15, '127.0.0.1', '2016-01-01 00:00:00', 'imageQuiSeraBloquee.png', 'image_15.png', 4239, 400, 640, '0000-00-00', 0, 0, '97a3a88502d6-theSameMd5-97a3a88502d6', 0, 0, 0, '127.0.0'),
|
||||
(16, '127.0.0.1', '2016-01-01 00:00:00', 'imageAvecMemeMd5QuiDoitEtreBloquee.png', 'image_16.png', 4239, 400, 640, '0000-00-00', 0, 0, '97a3a88502d6-theSameMd5-97a3a88502d6', 0, 0, 0, '127.0.0'),
|
||||
(17, '127.0.0.1', '2023-01-01 00:00:00', 'imagePeuAfficheeMaisMignatureBeaucoupAffichee.png', 'image_17.png', 4239, 400, 640, '0000-00-00', 1000, 1000, 'not-used--be5e3e8d65ecefdc0dbcca', 0, 0, 0, '127.0.0');
|
||||
|
||||
--
|
||||
-- Image signalée
|
||||
--
|
||||
INSERT INTO `images` (`id`, `ip_envoi`, `date_envoi`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`) VALUES
|
||||
(17, '127.0.0.1', '2008-01-01 00:00:00', 'imageSignalee.png', 'imageSignalee.png', 4239, 400, 640, NULL, 0, 0, 'd456d1b6582a15f0f458006898b40e29', 0, 1);
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(18, '127.0.0.1', '2008-01-01 00:00:00', 'test.webp', 'image_18.png', 4239, 400, 640, '0000-00-00', 0, 0, 'to-be-calculatedto-be-calculated', 0, 1, 0, '127.0.1');
|
||||
|
||||
--
|
||||
-- Image bloquée
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(19, '10.10.10.10', '2016-01-01 00:00:00', 'imageDejaBloquee.gif', 'image_19.gif', 146, 25, 37, '0000-00-00', 0, 0, 'to-be-calculatedto-be-calculated', 1, 0, 0, '10.10.10');
|
||||
|
||||
--
|
||||
-- Image du même réseau que celle bloquée
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(20, '10.10.10.200', '2016-01-01 00:00:00', 'imageMemeReseauQueDejaBloquee.gif', 'image_20.gif', 146, 25, 37, '0000-00-00', 751, 0, 'not-used--dea392173d746c107beda4', 0, 0, 0, '10.10.10');
|
||||
|
||||
--
|
||||
-- Réputation des réseaux
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(21, '192.168.0.1', '2024-01-01 00:00:00', 'Capture.jpg', 'image_21.jpg', 1, 1, 1, '0000-00-00', 0, 0, 'not-used--ab4d682db12defa28f09a6', 1, 0, 0, '192.168.0'),
|
||||
(22, '192.168.0.1', '2024-01-01 00:00:00', 'Capture.jpg', 'image_22.jpg', 1, 1, 1, '0000-00-00', 0, 0, 'not-used--009a3908f941f94f9d9d5a', 1, 0, 0, '192.168.0'),
|
||||
(23, '192.168.0.1', '2024-01-01 00:00:00', 'Capture.jpg', 'image_23.jpg', 1, 1, 1, '0000-00-00', 0, 0, 'not-used--17dc9dab5ec4aaf13cb5d8', 1, 0, 0, '192.168.0'),
|
||||
(24, '192.168.0.1', '2024-01-01 00:00:00', 'Capture.jpg', 'image_24.jpg', 1, 1, 1, '0000-00-00', 0, 0, 'not-used--1a18d35e0fed1f2963ac77', 1, 0, 0, '192.168.0'),
|
||||
(25, '192.168.0.1', '2024-01-01 00:00:00', 'Capture.jpg', 'image_25.jpg', 1, 1, 1, '0000-00-00', 0, 0, 'not-used--4dd6365d4aea4e3bde009f', 1, 0, 0, '192.168.0'),
|
||||
(26, '192.168.100.1', '2024-01-01 00:00:00', 'Capture.jpg', 'image_26.jpg', 1, 1, 1, '0000-00-00', 0, 0, 'not-used--48c026fca13b23c786ed87', 1, 0, 0, '192.168.100');
|
||||
|
||||
--
|
||||
-- Image qui sera trop affichée EN PROJECTION
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(27, '127.0.3.1', (NOW() - INTERVAL 2 HOUR), 'image_trop_affichee_en_projection.png', 'image_27.png', 1, 1, 1, NOW(), 5000, 5000, 'not-used--ab48e8f727e3329aaa6cf4', 0, 0, 0, '127.0.3');
|
||||
|
||||
--
|
||||
-- Images qui seront bloquées
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(28, '127.0.1.1', NOW(), 'image_a_bloquer_en_prog.png', 'image_28.png', 1, 1, 1, NOW(), 50, 50, 'ab5fe1f77dfb-theSameMd5-ab5fe1f77dfb', 0, 0, 0, '127.0.1'),
|
||||
(29, '127.0.1.1', NOW(), 'image_qui_sera_aussi_bloquee_car_md5_identique.png', 'image_29.png', 1, 1, 1, NOW(), 50, 50, 'ab5fe1f77dfb-theSameMd5-ab5fe1f77dfb', 0, 0, 1, '127.0.1');
|
||||
|
||||
--
|
||||
-- Images qui seront validées
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(30, '127.0.0.1', NOW(), 'image_a_valider_prog.png', 'image_30.png', 1, 1, 1, NOW(), 50, 50, 'f3a7c514d2-theSameMd5-f3a7c514d2', 0, 0, 0, '127.0.0'),
|
||||
(31, '127.0.0.1', NOW(), 'image_a_valider_prog.png', 'image_31.png', 1, 1, 1, NOW(), 50, 50, 'f3a7c514d2-theSameMd5-f3a7c514d2', 0, 1, 0, '127.0.0'),
|
||||
(32, '127.0.0.1', NOW(), 'image_a_valider_prog.png', 'image_32.png', 1, 1, 1, NOW(), 50, 50, 'f3a7c514d2-theSameMd5-f3a7c514d2', 0, 0, 1, '127.0.0');
|
||||
|
||||
--
|
||||
-- Image qui sera bloqué lors de son affichage avec un User-Agent malveillant
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(33, '127.0.4.1', NOW(), 'imageQuiSeraSignaleeParUserAgent.png', 'image_33.png', 1, 1, 1, '0000-00-00', 0, 0, 'd0a77eeeff5ef764505fe5b119b913bf', 0, 0, 0, '127.0.4');
|
||||
|
||||
--
|
||||
-- Image beaucoup trop affichée
|
||||
--
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`) VALUES
|
||||
(34, '127.0.0.1', DATE_SUB(NOW(), INTERVAL 3 DAY), 'imageBeaucoupTropAffichee.png', 'image_34.png', 1, 1, 1, NOW(), 99999999, 99999999, 'not-used--fd9cb5a0afba67138bd328', 0, 0, 0, '127.0.0');
|
||||
|
||||
--
|
||||
-- Agrandir la taille du champ pour bien gérer le _bootstrap
|
||||
--
|
||||
ALTER TABLE `thumbnails` MODIFY `new_name` VARCHAR(50) ;
|
||||
--
|
||||
-- Miniatures à supprimer
|
||||
--
|
||||
INSERT INTO `thumbnails` (`id`, `id_image`, `date_creation`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`) VALUES
|
||||
(1, 14, '2016-01-01', '14777777.png', 10316, 100, 100, '2016-01-01', 19, 0, '031328c1a7ffe7eed0a2cab4eca05a63'),
|
||||
(2, 14, '2016-01-01', '147777772.png', 10316, 200, 200, '2016-01-01', 19, 0, '278a70a02e036cc85e0d7e605fdc517f');
|
||||
INSERT INTO `thumbnails` (`id`, `images_id`, `date_action`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`) VALUES
|
||||
(1, 14, '2016-01-01', 'image_a_supprimerMultiple-100x100.png', 10316, 100, 100, '2016-01-01', 19, 0, 'to-be-calculatedto-be-calculated'),
|
||||
(2, 14, '2016-01-01', 'image_a_supprimerMultiple-200x200.png', 10316, 200, 200, '2016-01-01', 19, 0, 'to-be-calculatedto-be-calculated');
|
||||
--
|
||||
-- Miniature beaucoup affichée
|
||||
--
|
||||
INSERT INTO `thumbnails` (`id`, `images_id`, `date_action`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`) VALUES
|
||||
(3, 20, '2023-01-01', '14777777.png', 10316, 100, 100, '2023-01-01', 999999999999, 999999999999, 'not-used--f12d4a42776aba3a16761e');
|
||||
|
||||
|
||||
--
|
||||
-- Possessions
|
||||
--
|
||||
INSERT INTO `possede` (`image_id`, `pk_membres`) VALUES ('11', '2'),
|
||||
INSERT INTO `possede` (`images_id`, `membres_id`) VALUES ('11', '2'),
|
||||
('14', '1');
|
||||
|
||||
|
||||
--
|
||||
-- Second compte utilisateur
|
||||
--
|
||||
INSERT INTO `membres` (`id`, `email`, `login`, `password`, `date_inscription`, `ip_inscription`, `lvl`) VALUES
|
||||
(2, 'john.doe2@example.com', 'user', '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', DATE(NOW()), '127.0.0.1', 1);
|
||||
INSERT INTO `membres` (`id`, `email`, `login`, `password`, `date_action`, `remote_addr`, `lvl`, `token`) VALUES
|
||||
(2, 'john.doe2@example.com', 'user', '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', DATE(NOW()), '127.0.0.1', 1, '');
|
BIN
__tests/images/aImporter/imageBleue10.png
Normal file
After Width: | Height: | Size: 555 B |
BIN
__tests/images/aImporter/imageDejaBloquee.gif
Normal file
After Width: | Height: | Size: 146 B |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
BIN
__tests/images/aImporter/test.webp
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
__tests/images/animated-image.webp
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 309 KiB |
BIN
__tests/images/image_15000x15000.png
Normal file
After Width: | Height: | Size: 673 KiB |
BIN
__tests/images/image_33.png
Normal file
After Width: | Height: | Size: 864 B |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
BIN
__tests/images/rotation_original.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
__tests/images/rotation_original.jpg
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
__tests/images/rotation_original.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
__tests/images/rotation_original.webp
Normal file
After Width: | Height: | Size: 790 B |
BIN
__tests/images/rotation_original.xcf
Normal file
1
__tests/ipv4.txt
Normal file
1
__tests/ipv6.txt
Normal file
162
a_propos.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,89 +24,91 @@ namespace ImageHeberg;
|
|||
require 'config/config.php';
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>A propos</small></h1>
|
||||
<h1 class="mb-3"><small>A propos</small></h1>
|
||||
|
||||
<div class="card card-default">
|
||||
<div class="card-body">
|
||||
Ce site est administré par <a href="<?= _ADMINISTRATEUR_SITE_ ?>"><?= _ADMINISTRATEUR_NOM_ ?></a>
|
||||
<br />
|
||||
Pour toute demande ou information concernant ce site, merci d'utiliser
|
||||
<a href="/contact.php">le formulaire de contact</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Licences
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Auteur de l'outil : <a href="//www.anael.eu">Anael MOBILIA</a>
|
||||
<br />
|
||||
Le <a href="//github.com/AnaelMobilia/image-heberg.fr">code source est disponible</a> sous licence GNU GPLv3.
|
||||
<br />
|
||||
Graphismes : <a href="//getbootstrap.com/">Bootstrap</a>
|
||||
<br />
|
||||
Logos : <a href="//fontawesome.com">Font Awesome</a>
|
||||
<br />
|
||||
Technologies : PHP, MySQL, HTML5, CSS3
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Hébergeur
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Ce site est hébergé chez <a href="<?= _HEBERGEUR_SITE_ ?> "><?= _HEBERGEUR_NOM_ ?> </a>
|
||||
<br />
|
||||
Vous trouverez leur adresse et téléphone sur <a href="<?= _HEBERGEUR_SITE_ ?>">leur site internet</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseCNIL">
|
||||
Conservations de données à caractère privé
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseCNIL" class="collapse">
|
||||
<div class="card card-body">
|
||||
L'utilisation du service conduit à l'enregistrement de cookies techniques (gestion des sessions) sur votre ordinateur. Ces cookies seront supprimés lors de la fermeture de votre navigateur.
|
||||
<br />
|
||||
Votre adresse IP est enregistrée dans la base de données lors de l'envoi d'une image, de la création et à la connexion à votre espace membre.
|
||||
<br />
|
||||
La suppression d'une image envoyée sur le service conduit à la suppression de toutes les informations liées dans la base de données. Les images qui ne sont plus affichées depuis plus de
|
||||
<?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jours seront automatiquement effacées.
|
||||
<br />
|
||||
La suppression de votre compte entraine la suppression de toutes les informations liées à ce dernier.
|
||||
<br />
|
||||
Conformément à la directive 2006/24/CE sur la conservation des données, tous les accès au service sont enregistrés et conservés durant une durée d'au moins 12 mois et au plus 24 mois.
|
||||
<br />
|
||||
Aucune donnée n'est utilisée à but publicitaire, ni transmise à des tiers, ou réutilisée en dehors du présent service. L'ensemble des données sont stockées au sein de l'Union Européenne.
|
||||
<div class="card card-default">
|
||||
<div class="card-body">
|
||||
Ce site est administré par <a href="<?= _ADMINISTRATEUR_SITE_ ?>"><?= _ADMINISTRATEUR_NOM_ ?></a>
|
||||
<br/>
|
||||
Pour toute demande ou information concernant ce site, merci d'utiliser
|
||||
<a href="/contact.php">le formulaire de contact</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseCNIL2">
|
||||
Responsable du traitement : <?= _ADMINISTRATEUR_NOM_ ?>
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseCNIL2" class="collapse">
|
||||
<div class="card card-body">
|
||||
Les informations recueillies font l’objet d’un traitement informatique destiné à personnaliser votre utilisation du service.
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Licences
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Auteur de l'outil : <a href="//www.anael.eu">Anael MOBILIA</a>
|
||||
<br/>
|
||||
Le <a href="//github.com/AnaelMobilia/image-heberg.fr">code source est disponible</a> sous licence GNU GPLv3.
|
||||
<br/>
|
||||
Graphismes : <a href="//getbootstrap.com/">Bootstrap</a>
|
||||
<br/>
|
||||
Logos : <a href="//icons.getbootstrap.com/">Bootstrap Icons</a>
|
||||
<br/>
|
||||
IA de classification : <a href="//github.com/infinitered/nsfwjs">nsfwjs</a>
|
||||
<br />
|
||||
Vous n'êtes pas obligé de créer un espace membre pour utiliser le service.
|
||||
<br />
|
||||
Le destinataire des données est <?= _ADMINISTRATEUR_NOM_ ?>.
|
||||
<br />
|
||||
Conformément à la loi « informatique et libertés » du 6 janvier 1978 modifiée en 2004, vous bénéficiez d'un droit d'accès et de rectification aux informations qui vous concernent, que vous pouvez exercer en vous adressant à <?= _ADMINISTRATEUR_NOM_ ?> via le formulaire de contact.
|
||||
<br />
|
||||
Vous pouvez également, pour des motifs légitimes, vous opposer au traitement des données vous concernant.
|
||||
Technologies : PHP, MySQL, HTML5, CSS3
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Hébergeur
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Ce site est hébergé chez <a href="<?= _HEBERGEUR_SITE_ ?> "><?= _HEBERGEUR_NOM_ ?> </a>
|
||||
<br/>
|
||||
Vous trouverez leur adresse et téléphone sur <a href="<?= _HEBERGEUR_SITE_ ?>">leur site internet</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseCNIL">
|
||||
Conservations de données à caractère privé
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseCNIL" class="collapse">
|
||||
<div class="card card-body">
|
||||
L'utilisation du service conduit à l'enregistrement de cookies techniques (gestion des sessions) sur votre ordinateur. Ces cookies seront supprimés lors de la fermeture de votre navigateur.
|
||||
<br/>
|
||||
Votre adresse IP est enregistrée dans la base de données lors de l'envoi d'une image, de la création et à la connexion à votre espace membre.
|
||||
<br/>
|
||||
La suppression d'une image envoyée sur le service conduit à la suppression de toutes les informations liées dans la base de données. Les images qui ne sont plus affichées depuis plus de
|
||||
<?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jours seront automatiquement effacées.
|
||||
<br/>
|
||||
La suppression de votre compte entraine la suppression de toutes les informations liées à ce dernier.
|
||||
<br/>
|
||||
Conformément à la directive 2006/24/CE sur la conservation des données, tous les accès au service sont enregistrés et conservés durant une durée d'au moins 12 mois et au plus 24 mois.
|
||||
<br/>
|
||||
Aucune donnée n'est utilisée à but publicitaire, ni transmise à des tiers, ou réutilisée en dehors du présent service. L'ensemble des données sont stockées au sein de l'Union Européenne.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseCNIL2">
|
||||
Responsable du traitement : <?= _ADMINISTRATEUR_NOM_ ?>
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseCNIL2" class="collapse">
|
||||
<div class="card card-body">
|
||||
Les informations recueillies font l’objet d’un traitement informatique destiné à personnaliser votre utilisation du service.
|
||||
<br/>
|
||||
Vous n'êtes pas obligé de créer un espace membre pour utiliser le service.
|
||||
<br/>
|
||||
Le destinataire des données est <?= _ADMINISTRATEUR_NOM_ ?>.
|
||||
<br/>
|
||||
Conformément à la loi « informatique et libertés » du 6 janvier 1978 modifiée en 2004, vous bénéficiez d'un droit d'accès et de rectification aux informations qui vous concernent, que vous pouvez exercer en vous adressant à <?= _ADMINISTRATEUR_NOM_ ?> via le formulaire de contact.
|
||||
<br/>
|
||||
Vous pouvez également, pour des motifs légitimes, vous opposer au traitement des données vous concernant.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
96
abuse.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,70 +24,85 @@ namespace ImageHeberg;
|
|||
if (!defined('_PHPUNIT_')) {
|
||||
require 'config/config.php';
|
||||
}
|
||||
require _TPL_TOP_;
|
||||
|
||||
// Anti flood
|
||||
$maSession = new SessionObject();
|
||||
$msgErreur = '';
|
||||
|
||||
require _TPL_TOP_;
|
||||
|
||||
// En cas de validation du formulaire
|
||||
if (isset($_POST['Submit']) && $maSession->checkFlag()) {
|
||||
if (
|
||||
isset($_POST['Submit']) && $maSession->checkFlag()
|
||||
&& !empty($_POST['userMail']) && !empty($_POST['urlImage'])
|
||||
) {
|
||||
// Suivi du traitement
|
||||
$isTraitee = false;
|
||||
|
||||
// Vérification du bon format de l'adresse mail
|
||||
if (filter_var($_POST['userMail'], FILTER_VALIDATE_EMAIL) !== false) {
|
||||
// On essaie de matcher l'image
|
||||
$result = preg_match("#^.*\/([\d]*.[pngjpif]{3})$#", trim($_POST['urlImage']), $idImage);
|
||||
if ($result) {
|
||||
// On essaie de matcher l'image - nettoyage des paramètres
|
||||
$fileName = basename(parse_url(trim($_POST['urlImage']), PHP_URL_PATH));
|
||||
if (
|
||||
preg_match('#^[\d]+\.(?:' . implode('|', _ACCEPTED_EXTENSIONS_) . ')$#', $fileName)
|
||||
|| (_PHPUNIT_ && $fileName === 'image_15.png')
|
||||
) {
|
||||
// Suivi du traitement
|
||||
$isTraitee = true;
|
||||
// On flaggue l'image en signalée en BDD
|
||||
$monImage = new ImageObject($idImage[1]);
|
||||
$monImage->setSignalee(true);
|
||||
$monImage->sauver();
|
||||
|
||||
// On cherche les autres images avec le même MD5
|
||||
$images = MetaObject::getImageByMd5($monImage->getMd5());
|
||||
foreach ($images as $uneImage) {
|
||||
// On flaggue en signalée...
|
||||
$monImage = new ImageObject($uneImage);
|
||||
$monImage = new ImageObject($fileName);
|
||||
// Si l'image est approuvée, on ne la bloque pas en automatique
|
||||
if (!$monImage->isApprouvee()) {
|
||||
$monImage->setSignalee(true);
|
||||
$monImage->sauver();
|
||||
|
||||
// On cherche les autres images avec le même MD5
|
||||
$images = HelperAdmin::getImageByMd5($monImage->getMd5());
|
||||
foreach ($images as $uneImage) {
|
||||
// On flaggue en signalée...
|
||||
$monImage = new ImageObject($uneImage);
|
||||
$monImage->setSignalee(true);
|
||||
$monImage->sauver();
|
||||
}
|
||||
// Les miniatures reprennent automatiquement les informations de l'image parent
|
||||
} else {
|
||||
$isTraitee = false;
|
||||
}
|
||||
// Les miniatures reprennent automatiquement les informations de l'image parent
|
||||
}
|
||||
|
||||
// Gestion travis
|
||||
if (!_PHPUNIT_) {
|
||||
// Je complète le message avec l'IP de mon émeteur
|
||||
$message = "URL : " . $_POST['urlImage'];
|
||||
$message .= "\r\n\r\nBlocage automatique : " . ($result ? 'OK' : 'KO');
|
||||
$message .= "\r\n\r\nRaison : " . $_POST['raison'];
|
||||
$message .= "\r\n\r\nMessage : " . $_POST['userMessage'];
|
||||
$message .= "\r\n\r\n---------------------------------------------";
|
||||
$message .= "\r\n\r\nIP : " . $_SERVER['REMOTE_ADDR'];
|
||||
$message .= "\r\n\r\nBROWSER : " . $_SERVER['HTTP_USER_AGENT'];
|
||||
$message = 'URL : ' . $_POST['urlImage'];
|
||||
$message .= PHP_EOL . 'Blocage automatique : ' . ($isTraitee ? 'OK' : 'KO');
|
||||
$message .= PHP_EOL . 'Raison : ' . $_POST['raison'];
|
||||
$message .= PHP_EOL . 'Message : ' . $_POST['userMessage'];
|
||||
$message .= PHP_EOL . '---------------------------------------------';
|
||||
$message .= PHP_EOL . 'IP : ' . $_SERVER['REMOTE_ADDR'];
|
||||
$message .= PHP_EOL . 'BROWSER : ' . $_SERVER['HTTP_USER_AGENT'];
|
||||
$message .= PHP_EOL . 'DATE : ' . date('Y-m-d H:i:s');
|
||||
|
||||
// Tout va bien, on envoit un mail
|
||||
$subject = "[" . _SITE_NAME_ . "] - Signalement d'image";
|
||||
mail(_ADMINISTRATEUR_EMAIL_, $subject, $message, "From: " . $_POST['userMail']);
|
||||
$subject = '[' . _SITE_NAME_ . '] - Signalement d\'image';
|
||||
mail(_ADMINISTRATEUR_EMAIL_, $subject, $message, 'From: ' . $_POST['userMail']);
|
||||
$maSession->removeFlag();
|
||||
}
|
||||
// Retour utilisateur
|
||||
echo '<div class="alert alert-success">Votre signalement a été envoyé !</div>';
|
||||
echo '<div class="alert alert-success">Votre signalement a été envoyé, merci !</div>';
|
||||
} else {
|
||||
// Adresse mail invalide
|
||||
echo '<div class = "alert alert-danger">Votre adresse mail n\'est pas valide !<br /><pre>' . $_POST['userMail'] . '</pre></div>';
|
||||
}
|
||||
} else {
|
||||
// Premier affichage de la page
|
||||
if (!isset($_POST['Submit'])) {
|
||||
// Activation de la protection robot
|
||||
$maSession->setFlag();
|
||||
$msgErreur = '<div class="alert alert-danger">Votre adresse mail n\'est pas valide !<br /><pre>' . $_POST['userMail'] . '</pre></div>';
|
||||
}
|
||||
} elseif (!isset($_POST['Submit'])) {
|
||||
// Premier affichage de la page => activation de la protection robot
|
||||
$maSession->setFlag();
|
||||
}
|
||||
?>
|
||||
<?php if ($maSession->checkFlag()) : ?>
|
||||
<?php if (!isset($_POST['Submit']) || $maSession->checkFlag()) : ?>
|
||||
<h1 class="mb-3"><small>Signaler une image</small></h1>
|
||||
|
||||
<?= $msgErreur ?>
|
||||
<form method="post">
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="text" class="form-control" name="urlImage" id="urlImage" required="required" value="<?= (isset($_POST['urlImage'])) ? $_POST['urlImage'] : '' ?>">
|
||||
<input type="text" class="form-control" name="urlImage" id="urlImage" required="required" value="<?= $_POST['urlImage'] ?? '' ?>">
|
||||
<label for="urlImage">Adresse de l'image</label>
|
||||
<div class="form-text text-muted">
|
||||
Indiquer toute l'URL de l'image, telle qu'affichée dans le navigateur (<?= _URL_IMAGES_ . _IMAGE_BAN_ ?>).
|
||||
|
@ -97,21 +112,22 @@ if (isset($_POST['Submit']) && $maSession->checkFlag()) {
|
|||
<select name="raison" id="raison" class="form-select" required="required">
|
||||
<option value="" selected>-- Sélectionner une raison --</option>
|
||||
<option value="porno">Pornographie et érotisme</option>
|
||||
<option value="phishing">Spam et phishing</option>
|
||||
<option value="legislation">Non respect de la législation française (à préciser)</option>
|
||||
<option value="autre">Autre (à préciser)</option>
|
||||
</select>
|
||||
<label for="raison">Raison du signalement</label>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="email" class="form-control" name="userMail" id="userMail" required="required" value="<?= (isset($_POST['userMail'])) ? $_POST['userMail'] : '' ?>">
|
||||
<input type="email" class="form-control" name="userMail" id="userMail" required="required" value="<?= $_POST['userMail'] ?? '' ?>">
|
||||
<label for="userMail">Votre adresse courriel</label>
|
||||
<div class="form-text text-muted">Sera utilisée uniquement pour vous apporter une réponse.</div>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<textarea class="form-control" rows="5" name="userMessage" id="userMessage" placeholder="Informations complémentaires sur la raison de votre demande" required="required"><?= (isset($_POST['userMessage'])) ? $_POST['userMessage'] : '' ?></textarea>
|
||||
<textarea class="form-control" rows="5" name="userMessage" id="userMessage" placeholder="Informations complémentaires sur la raison de votre demande" required="required"><?= $_POST['userMessage'] ?? '' ?></textarea>
|
||||
<label for="userMessage">Votre message</label>
|
||||
</div>
|
||||
<button type="submit" name="Submit" class="btn btn-success">Envoyer</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
59
admin/abuse-network.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
if (!defined('_PHPUNIT_')) {
|
||||
require '../config/config.php';
|
||||
}
|
||||
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
|
||||
$listeIp = HelperAdmin::getBadNetworks();
|
||||
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Réseaux IP suspects</small></h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= count($listeIp) ?> réseau<?= (count($listeIp) > 1 ? 'x' : '') ?> d'addresses IP
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Réseau</th>
|
||||
<th>Nombre d'images bloquées</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbody">
|
||||
<?php foreach ((array)$listeIp as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= $key ?></td>
|
||||
<td><?= $value ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
180
admin/abuse.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
if (!defined('_PHPUNIT_')) {
|
||||
require '../config/config.php';
|
||||
}
|
||||
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Gestion des abus</small></h1>
|
||||
<?php
|
||||
|
||||
$message = '';
|
||||
|
||||
$tabTables = [];
|
||||
// Action à effectuer sur une image
|
||||
if (isset($_GET['idImage']) && is_numeric($_GET['idImage'])) {
|
||||
$monImage = new ImageObject($_GET['idImage'], RessourceObject::SEARCH_BY_ID);
|
||||
if (isset($_GET['bloquer'])) {
|
||||
// Blocage de l'image
|
||||
$monImage->bloquer();
|
||||
$message .= 'Image ' . $monImage->getNomNouveau() . ' bloquée !';
|
||||
} elseif (isset($_GET['approuver'])) {
|
||||
// Approbation de l'image
|
||||
$monImage->approuver();
|
||||
$message .= 'Image ' . $monImage->getNomNouveau() . ' approuvée !';
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Images à traiter
|
||||
*/
|
||||
// Liste des images avec un ratio d'affichage incohérent
|
||||
$tabTables[] = [
|
||||
'legende' => 'affichée## > ' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ . ' fois/jour <small>(blocage automatique à ' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ . '</small>)',
|
||||
'values' => HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_)
|
||||
];
|
||||
// Liste des images avec un ratio d'affichage incohérent EN PROJECTION
|
||||
$tabTables[] = [
|
||||
'legende' => 'projetée## avec un nombre d\'affichages > ' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ . ' fois/jour <small>(blocage automatique à ' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ . '</small>)',
|
||||
'values' => HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_, false, true)
|
||||
];
|
||||
// Liste des images suspectes avec un ratio d'affichage incohérent
|
||||
$tabTables[] = [
|
||||
'legende' => '<b>suspecte##</b> affichée## > ' . (_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_) . ' fois/jour <small>(blocage automatique à ' . (_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_) . '</small>)',
|
||||
'values' => HelperAdmin::getImagesTropAffichees((_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_), true)
|
||||
];
|
||||
// Liste des images suspectes avec un ratio d'affichage incohérent EN PROJECTION
|
||||
$tabTables[] = [
|
||||
'legende' => '<b>suspecte##</b> projetée## avec un nombre d\'affichages > ' . (_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_) . ' fois/jour <small>(blocage automatique à ' . (_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_) . '</small>)',
|
||||
'values' => HelperAdmin::getImagesTropAffichees((_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_), true, true)
|
||||
];
|
||||
// Liste des images signalées
|
||||
$tabTables[] = [
|
||||
'legende' => 'signalée##',
|
||||
'values' => HelperAdmin::getImagesSignalees()
|
||||
];
|
||||
// Liste des images suspectes
|
||||
$tabTables[] = [
|
||||
'legende' => 'suspecte##',
|
||||
'values' => HelperAdmin::getImagesPotentiellementIndesirables()
|
||||
];
|
||||
// Liste des images approuvables
|
||||
$tabTables[] = [
|
||||
'legende' => 'approuvable##',
|
||||
'values' => HelperAdmin::getImagesPotentiellementApprouvables()
|
||||
];
|
||||
// Liste de TOUTES les images avec un ratio d'affichage abusif
|
||||
$tabTables[] = [
|
||||
'legende' => 'affichée## > ' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_ABUSIF_ . ' fois/jour',
|
||||
'values' => HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_ABUSIF_, false, true, true)
|
||||
];
|
||||
}
|
||||
/**
|
||||
* Recherche
|
||||
*/
|
||||
$tabSearch = [
|
||||
'Adresse IP' => 'SELECT new_name FROM images WHERE remote_addr LIKE \'%##value##%\' ORDER BY id DESC',
|
||||
'Nom originel' => 'SELECT new_name FROM images WHERE old_name LIKE \'%##value##%\' ORDER BY id DESC',
|
||||
'Nouveau nom' => 'SELECT new_name FROM images WHERE new_name LIKE \'%##value##%\' ORDER BY id DESC',
|
||||
'Utilisateur' => 'SELECT im.new_name FROM images im LEFT JOIN possede po ON po.images_id = im.id WHERE po.membres_id = \'##value##\' ORDER BY im.id DESC',
|
||||
'Bloquée' => 'SELECT new_name FROM images WHERE isBloquee = \'1\' ORDER BY id DESC',
|
||||
'Approuvée' => 'SELECT new_name FROM images WHERE isApprouvee = \'1\' ORDER BY id DESC',
|
||||
];
|
||||
if (isset($_POST['Submit']) && !empty($_POST['champ']) && !empty($_POST['valeur'])) {
|
||||
$reqValue = trim(str_replace('\'', '_', $_POST['valeur']));
|
||||
$req = str_replace('##value##', $reqValue, $tabSearch[$_POST['champ']]);
|
||||
array_unshift($tabTables, [
|
||||
'legende' => 'trouvée## -> recherche sur le champ "' . $_POST['champ'] . '" = "' . $_POST['valeur'] . '"',
|
||||
'values' => HelperAdmin::queryOnNewName($req)
|
||||
]);
|
||||
}
|
||||
?>
|
||||
<?php if (!empty($message)) : ?>
|
||||
<div class="alert alert-success">
|
||||
<?= $message ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="alert alert-info">
|
||||
<form method="post">
|
||||
<div class="mb-3 form-floating">
|
||||
<select name="champ" id="champ" class="form-select" required="required">
|
||||
<option value="" selected>-- Sélectionner un champ --</option>
|
||||
<?php foreach (array_keys($tabSearch) as $key) : ?>
|
||||
<option value="<?= $key ?>"><?= $key ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<label for="champ">Champ à utiliser</label>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="text" class="form-control" name="valeur" id="valeur" required="required" value="">
|
||||
<label for="valeur">Valeur recherchée</label>
|
||||
</div>
|
||||
<button type="submit" name="Submit" class="btn btn-success">Rechercher</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php foreach ($tabTables as $uneTable) : ?>
|
||||
<?php $mesImages = ImageObject::chargerMultiple($uneTable['values'], RessourceObject::SEARCH_BY_NAME);?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= count($uneTable['values']) ?> image<?= (count($uneTable['values']) > 1 ? 's' : '') . ' ' . str_replace('##', (count($uneTable['values']) > 1 ? 's' : ''), $uneTable['legende']) ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>Actions</th>
|
||||
<th class="text-break">Nom originel</th>
|
||||
<th class="text-break">Date d'envoi</th>
|
||||
<th class="text-break">IP envoi</th>
|
||||
<th class="text-break">Nb vues</th>
|
||||
<th class="text-break">Dernier affichage</th>
|
||||
<th class="text-break">Utilisateur</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($mesImages as $uneImage) : ?>
|
||||
<tr>
|
||||
<td><a href="<?= $uneImage->getURL(true) ?>?forceDisplay=1" target="_blank" style="<?= ($uneImage->isBloquee() ? 'text-decoration: line-through double red;' : '') . ($uneImage->isApprouvee() ? 'text-decoration: underline double green;' : '') ?>"><?= $uneImage->getNomNouveau() ?></a></td>
|
||||
<td>
|
||||
<a href="<?= _URL_ADMIN_ ?>abuse.php?approuver=1&idImage=<?= $uneImage->getId() ?>" title="Approuver"><span class="bi-hand-thumbs-up-fill" style="color: green"></span></a>
|
||||
<a href="<?= _URL_ADMIN_ ?>abuse.php?bloquer=1&idImage=<?= $uneImage->getId() ?>" title="Bloquer"><span class="bi-hand-thumbs-down-fill" style="color: red"></span></a>
|
||||
</td>
|
||||
<td class="text-break"><?= $uneImage->getNomOriginalFormate() ?></td>
|
||||
<td class="text-break"><?= $uneImage->getDateEnvoiFormatee() ?></td>
|
||||
<td class="text-break"><?= $uneImage->getIpEnvoi() ?></td>
|
||||
<td class="text-break"><?= $uneImage->getNbViewTotal() ?><small> (<?= $uneImage->getNbViewPerDay() ?>/jour)</small></td>
|
||||
<td class="text-break"><?= $uneImage->getLastViewFormate() ?></td>
|
||||
<td class="text-break"><?= $uneImage->getIdProprietaire() ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<?php endforeach; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
73
admin/cleanAccountsNeverUsed.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
require '../config/config.php';
|
||||
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Nettoyage des comptes jamais utilisés</small></h1>
|
||||
<?php
|
||||
|
||||
$message = '';
|
||||
|
||||
// Je récupère la liste des comptes jamais utilisés
|
||||
$listeComptes = HelperAdmin::getUnusedAccounts();
|
||||
$isPlural = ($listeComptes->count() > 1 ? 's' : '');
|
||||
|
||||
// Si l'effacement est demandé
|
||||
if (isset($_POST['effacer'])) :
|
||||
foreach ((array)$listeComptes as $value) {
|
||||
$message .= '<br />Suppression du compte ' . $value;
|
||||
|
||||
// Je crée mon objet et lance la suppression
|
||||
$monUtilisateur = new UtilisateurObject($value);
|
||||
$monUtilisateur->supprimer();
|
||||
}
|
||||
$message .= '<br />Effacement terminé !';
|
||||
?>
|
||||
<div class="alert alert-success">
|
||||
<?= $message ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $listeComptes->count() ?> compte<?= $isPlural ?> créé<?= $isPlural ?> il y a au moins <?= _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ ?> jour<?= _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ > 1 ? 's' : '' ?> et sans images associées
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php foreach ((array)$listeComptes as $value) : ?>
|
||||
<li><?= $value ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<form method="post">
|
||||
<button class="btn btn-danger" type="submit" name="effacer">
|
||||
<span class="bi-trash"></span>
|
||||
Effacer ce<?= $isPlural ?> compte<?= $isPlural ?>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -28,47 +28,47 @@ require '../config/config.php';
|
|||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Nettoyage des incohérences</small></h1>
|
||||
<h1 class="mb-3"><small>Nettoyage des incohérences</small></h1>
|
||||
<?php
|
||||
|
||||
$message = '';
|
||||
|
||||
// Je récupère la liste des images en BDD
|
||||
$listeImagesBDD = MetaObject::getAllImagesNameBDD();
|
||||
$listeImagesBDD = HelperAdmin::getAllImagesNameBDD();
|
||||
// Je récupère la liste des images sur le HDD
|
||||
$listeImagesHDD = MetaObject::getAllImagesNameHDD(_PATH_IMAGES_);
|
||||
$listeImagesHDD = HelperAdmin::getAllImagesNameHDD(_PATH_IMAGES_);
|
||||
|
||||
// Je recherche les erreurs sur les images
|
||||
// Pour chaque images en BDD
|
||||
$listeErreursImagesBDD = new ArrayObject(array_diff((array) $listeImagesBDD, (array) $listeImagesHDD));
|
||||
$listeErreursImagesBDD = new ArrayObject(array_diff((array)$listeImagesBDD, (array)$listeImagesHDD));
|
||||
// Pour chaque images en HDD
|
||||
$listeErreursImagesHDD = new ArrayObject(array_diff((array) $listeImagesHDD, (array) $listeImagesBDD));
|
||||
$listeErreursImagesHDD = new ArrayObject(array_diff((array)$listeImagesHDD, (array)$listeImagesBDD));
|
||||
|
||||
|
||||
// Je récupère la liste des miniatures en BDD
|
||||
$listeMiniaturesBDD = MetaObject::getAllMiniaturesNameBDD();
|
||||
$listeMiniaturesBDD = HelperAdmin::getAllMiniaturesNameBDD();
|
||||
// Je récupère la liste des miniatures en HDD
|
||||
$listeMiniaturesHDD = MetaObject::getAllImagesNameHDD(_PATH_MINIATURES_);
|
||||
$listeMiniaturesHDD = HelperAdmin::getAllImagesNameHDD(_PATH_MINIATURES_);
|
||||
|
||||
// Je recherche les erreurs sur les miniatures
|
||||
// Pour chaque miniatures en BDD
|
||||
$listeErreursMiniaturesBDD = new ArrayObject(array_diff((array) $listeMiniaturesBDD, (array) $listeMiniaturesHDD));
|
||||
$listeErreursMiniaturesBDD = new ArrayObject(array_diff((array)$listeMiniaturesBDD, (array)$listeMiniaturesHDD));
|
||||
// Pour chaque miniatures en HDD
|
||||
$listeErreursMiniaturesHDD = new ArrayObject(array_diff((array) $listeMiniaturesHDD, (array) $listeMiniaturesBDD));
|
||||
$listeErreursMiniaturesHDD = new ArrayObject(array_diff((array)$listeMiniaturesHDD, (array)$listeMiniaturesBDD));
|
||||
|
||||
|
||||
// Si l'effacement est demandé
|
||||
if (isset($_POST['effacer'])) :
|
||||
// Images uniquement en BDD
|
||||
foreach ((array) $listeErreursImagesBDD as $value) {
|
||||
foreach ((array)$listeErreursImagesBDD as $value) {
|
||||
$message .= '<br />Suppression de la BDD de l\'image ' . $value;
|
||||
|
||||
// Je crée mon objet et lance la suppression
|
||||
$monImage = new ImageObject($value);
|
||||
$monImage = new ImageObject($value, RessourceObject::SEARCH_BY_MD5);
|
||||
$monImage->supprimer();
|
||||
}
|
||||
// Images uniquement en HDD
|
||||
foreach ((array) $listeErreursImagesHDD as $value) {
|
||||
foreach ((array)$listeErreursImagesHDD as $value) {
|
||||
$message .= '<br />Suppression du disque de l\'image ' . $value;
|
||||
|
||||
// Suppression du fichier
|
||||
|
@ -77,16 +77,16 @@ if (isset($_POST['effacer'])) :
|
|||
unlink($pathFinal);
|
||||
}
|
||||
// Miniatures uniquement en BDD
|
||||
foreach ((array) $listeErreursMiniaturesBDD as $value) {
|
||||
foreach ((array)$listeErreursMiniaturesBDD as $value) {
|
||||
$message .= '<br />Suppression de la BDD de la miniature ' . $value;
|
||||
|
||||
// Je crée mon objet et lance la suppression
|
||||
$maMiniature = new MiniatureObject($value);
|
||||
$maMiniature = new MiniatureObject($value, RessourceObject::SEARCH_BY_MD5);
|
||||
$maMiniature->supprimer();
|
||||
}
|
||||
|
||||
// Miniatures uniquement en HDD
|
||||
foreach ((array) $listeErreursMiniaturesHDD as $value) {
|
||||
foreach ((array)$listeErreursMiniaturesHDD as $value) {
|
||||
$message .= '<br />Suppression du disque de la miniature ' . $value;
|
||||
|
||||
// Suppression du fichier
|
||||
|
@ -103,14 +103,11 @@ if (isset($_POST['effacer'])) :
|
|||
<?php else : ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $listeErreursImagesBDD->count() ?>
|
||||
image<?= ($listeErreursImagesBDD->count() > 1) ? 's' : '' ?>
|
||||
présente<?= ($listeErreursImagesBDD->count() > 1) ? 's' : '' ?>
|
||||
uniquement en BDD
|
||||
<?= $listeErreursImagesBDD->count() ?> image<?= ($listeErreursImagesBDD->count() > 1) ? 's' : '' ?> présente<?= ($listeErreursImagesBDD->count() > 1) ? 's' : '' ?> uniquement en BDD
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php foreach ((array) $listeErreursImagesBDD as $value) : ?>
|
||||
<?php foreach ((array)$listeErreursImagesBDD as $value) : ?>
|
||||
<li><?= $value ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
@ -118,14 +115,11 @@ if (isset($_POST['effacer'])) :
|
|||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $listeErreursImagesHDD->count() ?>
|
||||
image<?= ($listeErreursImagesHDD->count() > 1) ? 's' : '' ?>
|
||||
présente<?= ($listeErreursImagesHDD->count() > 1) ? 's' : '' ?>
|
||||
uniquement sur HDD
|
||||
<?= $listeErreursImagesHDD->count() ?> image<?= ($listeErreursImagesHDD->count() > 1) ? 's' : '' ?> présente<?= ($listeErreursImagesHDD->count() > 1) ? 's' : '' ?> uniquement sur HDD
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php foreach ((array) $listeErreursImagesHDD as $value) : ?>
|
||||
<?php foreach ((array)$listeErreursImagesHDD as $value) : ?>
|
||||
<li><?= $value ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
@ -133,14 +127,11 @@ if (isset($_POST['effacer'])) :
|
|||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $listeErreursMiniaturesBDD->count() ?>
|
||||
miniature<?= ($listeErreursMiniaturesBDD->count() > 1) ? 's' : '' ?>
|
||||
présente<?= ($listeErreursMiniaturesBDD->count() > 1) ? 's' : '' ?>
|
||||
uniquement en BDD
|
||||
<?= $listeErreursMiniaturesBDD->count() ?> miniature<?= ($listeErreursMiniaturesBDD->count() > 1) ? 's' : '' ?> présente<?= ($listeErreursMiniaturesBDD->count() > 1) ? 's' : '' ?> uniquement en BDD
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php foreach ((array) $listeErreursMiniaturesBDD as $value) : ?>
|
||||
<?php foreach ((array)$listeErreursMiniaturesBDD as $value) : ?>
|
||||
<li><?= $value ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
@ -148,14 +139,11 @@ if (isset($_POST['effacer'])) :
|
|||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $listeErreursMiniaturesHDD->count() ?>
|
||||
miniature<?= ($listeErreursMiniaturesHDD->count() > 1) ? 's' : '' ?>
|
||||
présente<?= ($listeErreursMiniaturesHDD->count() > 1) ? 's' : '' ?>
|
||||
uniquement sur HDD
|
||||
<?= $listeErreursMiniaturesHDD->count() ?> miniature<?= ($listeErreursMiniaturesHDD->count() > 1) ? 's' : '' ?> présente<?= ($listeErreursMiniaturesHDD->count() > 1) ? 's' : '' ?> uniquement sur HDD
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php foreach ((array) $listeErreursMiniaturesHDD as $value) : ?>
|
||||
<?php foreach ((array)$listeErreursMiniaturesHDD as $value) : ?>
|
||||
<li><?= $value ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
@ -163,10 +151,9 @@ if (isset($_POST['effacer'])) :
|
|||
</div>
|
||||
<form method="post">
|
||||
<button class="btn btn-danger" type="submit" name="effacer">
|
||||
<span class="fas fa-trash"></span>
|
||||
|
||||
Supprimer les incohérences
|
||||
<span class="bi-trash"></span>
|
||||
Supprimer les incohérences
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -22,53 +22,54 @@
|
|||
namespace ImageHeberg;
|
||||
|
||||
require '../config/config.php';
|
||||
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Nettoyage des fichiers jamais utilisés</small></h1>
|
||||
<h1 class="mb-3"><small>Nettoyage des fichiers jamais utilisés</small></h1>
|
||||
<?php
|
||||
|
||||
$message = '';
|
||||
|
||||
// Je récupère la liste des images jamais affichées
|
||||
$listeImages = MetaObject::getNeverUsedFiles();
|
||||
$listeImages = HelperAdmin::getNeverUsedFiles();
|
||||
$isPlural = ($listeImages->count() > 1 ? 's' : '');
|
||||
|
||||
// Si l'effacement est demandé
|
||||
if (isset($_POST['effacer'])) :
|
||||
foreach ((array) $listeImages as $value) {
|
||||
$message .= '<br />Suppression de l\'image ' . $value;
|
||||
|
||||
// Je crée mon objet et lance la suppression
|
||||
$monImage = new ImageObject($value);
|
||||
$mesImages = ImageObject::chargerMultiple($listeImages, RessourceObject::SEARCH_BY_NAME);
|
||||
/* @var ImageObject[] $mesImages */
|
||||
foreach ($mesImages as $monImage) {
|
||||
$message .= '<br />Suppression de l\'image ' . $monImage->getNomNouveau();
|
||||
$monImage->supprimer();
|
||||
}
|
||||
$message .= '<br />Effacement terminé !';
|
||||
?>
|
||||
<div class = "alert alert-success">
|
||||
<div class="alert alert-success">
|
||||
<?= $message ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $listeImages->count() ?> image(s) envoyée(s) il y a
|
||||
au moins <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?> jour(s) et jamais affichée(s)
|
||||
<?= $listeImages->count() ?> image<?= $isPlural ?> envoyée<?= $isPlural ?> il y a au moins <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?> jour<?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ > 1 ? 's' : '' ?> et jamais affichée<?= $isPlural ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php foreach ((array) $listeImages as $value) : ?>
|
||||
<li><?= $value ?></li>
|
||||
<?php foreach ((array)$listeImages as $value) : ?>
|
||||
<li>
|
||||
<a href="<?= str_replace('http:', 'https:', _URL_IMAGES_) . $value ?>?forceDisplay=1" target="_blank"><?= $value ?></a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<form method="post">
|
||||
<button class="btn btn-danger" type="submit" name="effacer">
|
||||
<span class="fas fa-trash"></span>
|
||||
|
||||
Effacer ces fichiers
|
||||
<span class="bi-trash"></span>
|
||||
Effacer ce<?= $isPlural ?> fichier<?= $isPlural ?>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -22,25 +22,26 @@
|
|||
namespace ImageHeberg;
|
||||
|
||||
require '../config/config.php';
|
||||
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Nettoyage des fichiers dormants</small></h1>
|
||||
<h1 class="mb-3"><small>Nettoyage des fichiers dormants</small></h1>
|
||||
<?php
|
||||
|
||||
$message = '';
|
||||
|
||||
// Je récupère la liste des images non affichées depuis xx jours
|
||||
$listeImages = MetaObject::getUnusedFiles();
|
||||
$listeImages = HelperAdmin::getUnusedFiles();
|
||||
$isPlural = ($listeImages->count() > 1 ? 's' : '');
|
||||
|
||||
// Si l'effacement est demandé
|
||||
if (isset($_POST['effacer'])) :
|
||||
foreach ((array) $listeImages as $value) {
|
||||
$message .= '<br />Suppression de l\'image ' . $value;
|
||||
|
||||
// Je crée mon objet et lance la suppression
|
||||
$monImage = new ImageObject($value);
|
||||
$mesImages = ImageObject::chargerMultiple($listeImages, RessourceObject::SEARCH_BY_NAME);
|
||||
/* @var ImageObject[] $mesImages */
|
||||
foreach ($mesImages as $monImage) {
|
||||
$message .= '<br />Suppression de l\'image ' . $monImage->getNomNouveau();
|
||||
$monImage->supprimer();
|
||||
}
|
||||
$message .= '<br />Effacement terminé !';
|
||||
|
@ -51,24 +52,24 @@ if (isset($_POST['effacer'])) :
|
|||
<?php else : ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $listeImages->count() ?> image(s) non affichée(s)
|
||||
depuis au moins <?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jour(s).
|
||||
<?= $listeImages->count() ?> image<?= $isPlural ?> non affichée<?= $isPlural ?> depuis au moins <?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jour<?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ > 1 ? 's' : '' ?>.
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php foreach ((array) $listeImages as $value) : ?>
|
||||
<li><?= $value ?></li>
|
||||
<?php foreach ((array)$listeImages as $value) : ?>
|
||||
<li>
|
||||
<a href="<?= str_replace('http:', 'https:', _URL_IMAGES_) . $value ?>?forceDisplay=1" target="_blank"><?= $value ?></a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<form method="post">
|
||||
<button class="btn btn-danger" type="submit" name="effacer">
|
||||
<span class="fas fa-trash"></span>
|
||||
|
||||
Effacer ces fichiers
|
||||
<span class="bi-trash"></span>
|
||||
Effacer ce<?= $isPlural ?> fichier<?= $isPlural ?>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
123
admin/index.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -26,54 +26,77 @@ require '../config/config.php';
|
|||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Panneau d'administration</small></h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Gestion du site
|
||||
<h1 class="mb-3"><small>Panneau d'administration</small></h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Gestion du site
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<a href="<?= _URL_ADMIN_ ?>abuse.php" class="btn btn-success">
|
||||
<span class="bi-radioactive"></span>
|
||||
Images à vérifier
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>lastUpload.php" class="btn btn-success">
|
||||
<span class="bi-file-earmark-image"></span>
|
||||
Derniers fichiers envoyés
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>nsfwjs.php" class="btn btn-success">
|
||||
<span class="bi-file-earmark-bar-graph"></span>
|
||||
IA - Catégorisation nsfwjs
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>abuse-network.php" class="btn btn-success">
|
||||
<span class="bi-cpu"></span>
|
||||
Réseaux suspects
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>validate.php" class="btn btn-success">
|
||||
<span class="bi-cloud-check"></span>
|
||||
Vérifier la configuration
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>cleanFilesNeverUsed.php" class="btn btn-warning">
|
||||
<span class="bi-file-earmark-x"></span>
|
||||
Supprimer les images jamais affichées et envoyées depuis plus de <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?> jour<?= (_DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ > 1) ? 's' : '' ?>
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>cleanInactiveFiles.php" class="btn btn-warning">
|
||||
<span class="bi-file-earmark-x-fill"></span>
|
||||
Supprimer les images non affichées depuis plus de <?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jour<?= (_DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ > 1) ? 's' : '' ?>
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>cleanAccountsNeverUsed.php" class="btn btn-warning">
|
||||
<span class="bi-person-x"></span>
|
||||
Supprimer les comptes créés il y a plus de <?= _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ ?> jour<?= (_DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ > 1) ? 's' : '' ?> et sans images associées
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<a href="<?= _URL_ADMIN_ ?>validate.php" class="btn btn-success">
|
||||
<span class="fas fa-list-alt"></span>
|
||||
|
||||
Vérifier la configuration
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br />
|
||||
<a href="<?= _URL_ADMIN_ ?>cleanFilesNeverUsed.php" class="btn btn-warning">
|
||||
<span class="fas fa-trash"></span>
|
||||
|
||||
Supprimer les images jamais affichées et envoyées depuis
|
||||
plus de <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?>
|
||||
jour<?= (_DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ > 1 ) ? 's' : '' ?>
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br />
|
||||
<a href="<?= _URL_ADMIN_ ?>cleanInactiveFiles.php" class="btn btn-warning">
|
||||
<span class="fas fa-trash-alt"></span>
|
||||
|
||||
Supprimer les images non affichées depuis
|
||||
plus de <?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?>
|
||||
jour<?= (_DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ > 1 ) ? 's' : '' ?>
|
||||
</a>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Gestion technique
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<a href="<?= _URL_ADMIN_ ?>listeFichiers.php" class="btn btn-default">
|
||||
<span class="bi-list-check"></span>
|
||||
|
||||
Lister les fichiers présents sur le disque
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<a href="<?= _URL_ADMIN_ ?>cleanErrors.php" class="btn btn-default">
|
||||
<span class="bi-database-fill-check"></span>
|
||||
|
||||
Vérifier la cohérence disque et BDD
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Gestion technique
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<a href="<?= _URL_ADMIN_ ?>listeFichiers.php" class="btn btn-default">
|
||||
<span class="fas fa-list-alt"></span>
|
||||
|
||||
Lister les fichiers présents sur le disque
|
||||
</a>
|
||||
<div class="clearfix"></div>
|
||||
<br />
|
||||
<a href="<?= _URL_ADMIN_ ?>cleanErrors.php" class="btn btn-default">
|
||||
<span class="fas fa-check"></span>
|
||||
|
||||
Vérifier la cohérence disque et BDD
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
134
admin/lastUpload.php
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
if (!defined('_PHPUNIT_')) {
|
||||
require '../config/config.php';
|
||||
}
|
||||
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Derniers fichiers envoyés</small></h1>
|
||||
<?php
|
||||
|
||||
$message = '';
|
||||
|
||||
$table = [
|
||||
'legende' => 'trouvée##',
|
||||
'values' => new ArrayObject(),
|
||||
];
|
||||
// Action à effectuer sur une image
|
||||
if (isset($_GET['idImage']) && is_numeric($_GET['idImage'])) {
|
||||
$monImage = new ImageObject($_GET['idImage'], RessourceObject::SEARCH_BY_ID);
|
||||
if (isset($_GET['bloquer'])) {
|
||||
// Blocage de l'image
|
||||
$monImage->bloquer();
|
||||
$message .= 'Image ' . $monImage->getNomNouveau() . ' bloquée !';
|
||||
} elseif (isset($_GET['approuver'])) {
|
||||
// Approbation de l'image
|
||||
$monImage->approuver();
|
||||
$message .= 'Image ' . $monImage->getNomNouveau() . ' approuvée !';
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Images à traiter
|
||||
*/
|
||||
$idStart = 0;
|
||||
if (!empty($_GET['nextId']) && preg_match('#^[0-9]+$#', $_GET['nextId'])) {
|
||||
$idStart = (int)$_GET['nextId'];
|
||||
}
|
||||
$req = 'SELECT MAX(new_name) as new_name FROM images' . ($idStart !== 0 ? ' WHERE id < ' . $idStart : '') . ' GROUP BY md5 ORDER BY date_action DESC LIMIT 50';
|
||||
$table['values'] = HelperAdmin::queryOnNewName($req);
|
||||
}
|
||||
$isPlural = false;
|
||||
if (count($table['values']) > 1) {
|
||||
$isPlural = true;
|
||||
}
|
||||
$lastId = '';
|
||||
// Charger les objets concernés
|
||||
$mesImages = ImageObject::chargerMultiple($table['values'], RessourceObject::SEARCH_BY_NAME, false);
|
||||
?>
|
||||
<?php if (!empty($message)) : ?>
|
||||
<div class="alert alert-success">
|
||||
<?= $message ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= count($table['values']) ?> image<?= ($isPlural ? 's' : '') . ' ' . str_replace('##', ($isPlural ? 's' : ''), $table['legende']) ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>Actions</th>
|
||||
<th class="text-break">Nom originel</th>
|
||||
<th class="text-break">Date d'envoi</th>
|
||||
<th class="text-break">IP envoi</th>
|
||||
<th class="text-break">Nb vues</th>
|
||||
<th class="text-break">Dernier affichage</th>
|
||||
<th class="text-break">Utilisateur</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($mesImages as $uneImage) : ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?= (($uneImage->isSuspecte() || $uneImage->isSignalee()) && !$uneImage->isBloquee() && !$uneImage->isApprouvee() ? '<span class="bi-exclamation-square-fill" style="color:red;"></span>' : '') ?>
|
||||
<?php if (!$uneImage->isApprouvee()): ?>
|
||||
<?php if ($uneImage->getNbViewPerDay() >= _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_): ?>
|
||||
<span class="bi-exclamation-diamond" style="color: orange"></span>
|
||||
<?php elseif ($uneImage->getNbViewPerDay() >= _ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_): ?>
|
||||
<span class="bi-exclamation-circle" style="color: lightblue"></span>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<a href="<?= $uneImage->getURL(true) ?>?forceDisplay=1" target="_blank" style="<?= ($uneImage->isBloquee() ? 'text-decoration: line-through double red;' : '') ?><?= ($uneImage->isApprouvee() ? 'text-decoration: underline double green;' : '') ?>"><?= $uneImage->getNomNouveau() ?></a></td>
|
||||
<td>
|
||||
<a href="<?= _URL_ADMIN_ ?>lastUpload.php?approuver=1&idImage=<?= $uneImage->getId() . ($idStart !== 0 ? '&nextId=' . $idStart : "") ?>" title="Approuver"><span class="bi-hand-thumbs-up-fill" style="color: green"></span></a>
|
||||
<a href="<?= _URL_ADMIN_ ?>lastUpload.php?bloquer=1&idImage=<?= $uneImage->getId() . ($idStart !== 0 ? '&nextId=' . $idStart : "") ?>" title="Bloquer"><span class="bi-hand-thumbs-down-fill" style="color: red"></span></a>
|
||||
</td>
|
||||
<td class="text-break"><?= $uneImage->getNomOriginalFormate() ?></td>
|
||||
<td class="text-break"><?= $uneImage->getDateEnvoiFormatee() ?></td>
|
||||
<td class="text-break"><?= $uneImage->getIpEnvoi() ?></td>
|
||||
<td><?= $uneImage->getNbViewTotal() ?><small> (<?= $uneImage->getNbViewPerDay() ?>/jour)</small></td>
|
||||
<td class="text-break"><?= $uneImage->getLastViewFormate() ?></td>
|
||||
<td class="text-break"><?= $uneImage->getIdProprietaire() ?></td>
|
||||
</tr>
|
||||
<?php $lastId = $uneImage->getId() ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="<?= _URL_ADMIN_ ?>lastUpload.php?nextId=<?= $lastId ?>" class="btn btn-primary"><span class="bi-arrow-left"></span> </a>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -26,35 +26,36 @@ require '../config/config.php';
|
|||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Images présentes sur le disque</small></h1>
|
||||
<ul>
|
||||
<?php
|
||||
<h1 class="mb-3"><small>Images présentes sur le disque</small></h1>
|
||||
<ul>
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Scan récursif
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function getScandirRecursif($path)
|
||||
{
|
||||
$monRetour = '<ul>';
|
||||
/**
|
||||
* Scan récursif
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
function getScandirRecursif(string $path): string
|
||||
{
|
||||
$monRetour = '<ul>';
|
||||
|
||||
// Scanne le répertoire fourni
|
||||
$scan_rep = scandir($path);
|
||||
// Pour chaque item
|
||||
foreach ($scan_rep as $item) {
|
||||
if ($item !== '.' && $item !== '..') {
|
||||
$monRetour .= '<li>' . $path . $item . '</li>';
|
||||
if (is_dir($path . $item)) {
|
||||
// Appel récursif
|
||||
$monRetour .= getScandirRecursif($path . $item . '/');
|
||||
// Scanne le répertoire fourni
|
||||
$scan_rep = scandir($path);
|
||||
// Pour chaque item
|
||||
foreach ($scan_rep as $item) {
|
||||
if ($item !== '.' && $item !== '..') {
|
||||
$monRetour .= '<li>' . $path . $item . '</li>';
|
||||
if (is_dir($path . $item)) {
|
||||
// Appel récursif
|
||||
$monRetour .= getScandirRecursif($path . $item . '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
$monRetour .= '</ul>';
|
||||
return $monRetour;
|
||||
}
|
||||
$monRetour .= '</ul>';
|
||||
return $monRetour;
|
||||
}
|
||||
echo getScandirRecursif(_PATH_IMAGES_);
|
||||
?>
|
||||
</ul>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
|
||||
echo getScandirRecursif(_PATH_IMAGES_);
|
||||
?>
|
||||
</ul>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
139
admin/nsfwjs.php
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
if (!defined('_PHPUNIT_')) {
|
||||
require '../config/config.php';
|
||||
}
|
||||
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>NSFWJS</small></h1>
|
||||
<?php
|
||||
|
||||
$message = '';
|
||||
|
||||
// Action à effectuer sur une image
|
||||
if (isset($_GET['idImage']) && is_numeric($_GET['idImage'])) {
|
||||
$monImage = new ImageObject($_GET['idImage'], RessourceObject::SEARCH_BY_ID);
|
||||
if (isset($_GET['bloquer'])) {
|
||||
// Blocage de l'image
|
||||
$monImage->bloquer();
|
||||
$message .= 'Image ' . $monImage->getNomNouveau() . ' bloquée !';
|
||||
} elseif (isset($_GET['approuver'])) {
|
||||
// Approbation de l'image
|
||||
$monImage->approuver();
|
||||
$message .= 'Image ' . $monImage->getNomNouveau() . ' approuvée !';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Images à traiter
|
||||
*/
|
||||
$idStart = 0;
|
||||
if (!empty($_GET['nextId']) && is_numeric($_GET['nextId'])) {
|
||||
$idStart = trim(str_replace('\'', '_', $_GET['nextId']));
|
||||
}
|
||||
$req = 'SELECT new_name FROM images' . ($idStart !== 0 ? ' WHERE id < ' . $idStart : '') . ' ORDER BY id DESC LIMIT 50';
|
||||
$table = [
|
||||
'legende' => 'trouvée##',
|
||||
'values' => HelperAdmin::queryOnNewName($req)
|
||||
];
|
||||
// Charger les objets concernés
|
||||
$mesImages = ImageObject::chargerMultiple($table['values'], RessourceObject::SEARCH_BY_NAME);
|
||||
?>
|
||||
<?php if (!empty($message)) : ?>
|
||||
<div class="alert alert-success">
|
||||
<?= $message ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= count($table['values']) ?> image<?= (count($table['values']) > 1 ? 's' : '') . ' ' . str_replace('##', (count($table['values']) > 1 ? 's' : ''), $table['legende']) ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>Actions</th>
|
||||
<th>Date d'envoi</th>
|
||||
<th>Catégorisation IA nsfwjs</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbody">
|
||||
<?php foreach ($mesImages as $uneImage) : ?>
|
||||
<tr>
|
||||
<td><a href="<?= $uneImage->getURL(true) ?>?forceDisplay=1" target="_blank" style="<?= ($uneImage->isBloquee() ? 'text-decoration: line-through double red;' : '') . ($uneImage->isApprouvee() ? 'text-decoration: underline double green;' : '') ?>"><?= $uneImage->getNomNouveau() ?></a></td>
|
||||
<td>
|
||||
<a href="<?= _URL_ADMIN_ ?>lastUpload.php?approuver=1&idImage=<?= $uneImage->getId() ?>" title="Approuver"><span class="bi-hand-thumbs-up-fill" style="color: green"></span></a>
|
||||
<a href="<?= _URL_ADMIN_ ?>lastUpload.php?bloquer=1&idImage=<?= $uneImage->getId() ?>" title="Bloquer"><span class="bi-hand-thumbs-down-fill" style="color: red"></span></a>
|
||||
</td>
|
||||
<td><?= $uneImage->getDateEnvoiFormatee() ?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="<?= _URL_ADMIN_ ?>nsfwjs.php?nextId=<?= $uneImage->getId() ?>" class="btn btn-primary"><span class="bi-arrow-left"></span> </a>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/nsfwjs"></script>
|
||||
|
||||
<script type="module">
|
||||
// Forcer le mode "Production" de tensorflow
|
||||
tf.enableProdMode();
|
||||
// Modèle récupéré de https://github.com/infinitered/nsfwjs/tree/master/example/nsfw_demo/public/quant_mid
|
||||
const model = await nsfwjs.load('<?=_URL_ADMIN_ ?>nsfwjs_model_quant_mid/', {type: 'graph'});
|
||||
|
||||
// On itère sur le tableau HTML
|
||||
let tabTr = Array.from(document.getElementById("tbody").children);
|
||||
for (const unTr of tabTr) {
|
||||
let img = new Image();
|
||||
// Lien vers l'image
|
||||
img.src = unTr.children[0].children[0].href;
|
||||
console.log(img.src);
|
||||
// Attendre que la ressource soit chargée
|
||||
await img.decode();
|
||||
|
||||
// Classify the image -> une seule classification attendue en résultat
|
||||
const predictions = await model.classify(img, 1);
|
||||
console.log('Predictions: ', predictions);
|
||||
// Résultats
|
||||
let results = '';
|
||||
for (let unType of predictions) {
|
||||
results += unType.className + ' -> ' + Math.round(unType.probability * 100) + '%<br />';
|
||||
}
|
||||
// Injection de la valeur dans la page
|
||||
unTr.children[3].innerHTML = results;
|
||||
}
|
||||
</script>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
BIN
admin/nsfwjs_model_quant_mid/group1-shard1of2.bin
Normal file
2
admin/nsfwjs_model_quant_mid/group1-shard2of2.bin
Normal file
1
admin/nsfwjs_model_quant_mid/model.json
Normal file
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -26,53 +26,58 @@ require '../config/config.php';
|
|||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Vérification de la configuration du serveur</small></h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
PHP
|
||||
<h1 class="mb-3"><small>Vérification de la configuration du serveur</small></h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
PHP
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?= HelperSysteme::getPhpVersion() ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?= MetaObject::getPhpVersion() ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
MySQL
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?= HelperSysteme::getMysqlVersion() ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
MySQL
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Imagick
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?= HelperSysteme::getImagickVersion() ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?= MetaObject::getMysqlVersion() ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Accès aux répertoires protégés par .htaccess .
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Les valeurs doivent être de type "HTTP/*.* 403 Forbidden".
|
||||
<ul>
|
||||
<li>Répertoire config : <?= HelperSysteme::getStatusHTTP(_URL_CONFIG_) ?></li>
|
||||
<li>Répertoire admin : <?= HelperSysteme::getStatusHTTP(_URL_ADMIN_) ?></li>
|
||||
<li>Répertoire membre : <?= HelperSysteme::getStatusHTTP(_URL_MEMBRE_) ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Accès aux répertoires protégés par .htaccess .
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Les valeurs doivent être de type "HTTP *.* 403 Forbidden".
|
||||
<ul>
|
||||
<li>Répertoire config : <?= MetaObject::getStatusHTTP(_URL_CONFIG_) ?></li>
|
||||
<li>Répertoire admin : <?= MetaObject::getStatusHTTP(_URL_ADMIN_) ?></li>
|
||||
<li>Répertoire membre : <?= MetaObject::getStatusHTTP(_URL_MEMBRE_) ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Droits sur tous les dossiers dans files/
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Droits sur tous les dossiers dans files/
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<?php
|
||||
|
||||
$lesDroits = MetaObject::isRecursivelyWritable(_PATH_IMAGES_);
|
||||
foreach ((array) $lesDroits as $unItem) :
|
||||
?>
|
||||
<li><?= $unItem ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
$lesDroits = HelperSysteme::isRecursivelyWritable(_PATH_IMAGES_);
|
||||
foreach ((array)$lesDroits as $unItem) :
|
||||
?>
|
||||
<li><?= $unItem ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
require _TPL_BOTTOM_;
|
||||
?>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
129
cgu.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,65 +24,76 @@ namespace ImageHeberg;
|
|||
require 'config/config.php';
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Conditions Générales d'Utilisation de <?= _SITE_NAME_ ?></small></h1>
|
||||
<h1 class="mb-3"><small>Conditions Générales d'Utilisation de <?= _SITE_NAME_ ?></small></h1>
|
||||
|
||||
<div class="alert alert-success">Ces CGU sont modifiables sans préavis et à tout moment.</div>
|
||||
<div class="alert alert-success">Ces CGU sont modifiables sans préavis et à tout moment.</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Contenus autorisés
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Toutes images de type JPG, PNG, GIF.</li>
|
||||
<li>Contenu conforme à la législation française.</li>
|
||||
<li>Pornographie et érotisme non autorisés.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Propriétés de l'hébergement
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Gratuit.</li>
|
||||
<li>Traffic illimité <em>(hors abus)</em>.</li>
|
||||
<li>
|
||||
<b>Conservation :</b>
|
||||
<ul>
|
||||
<li>
|
||||
<?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?>
|
||||
jour<?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ > 1 ? 's' : '' ?>
|
||||
à compter de la dernière utilisation du fichier.
|
||||
</li>
|
||||
<li>
|
||||
A défaut, <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?>
|
||||
jour<?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ > 1 ? 's' : '' ?>
|
||||
après l'envoi <em>(si aucun affichage)</em>.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
Nombre d'images par compte : illimité.
|
||||
</li>
|
||||
<li>
|
||||
Les fichiers restent votre propriété.
|
||||
</li>
|
||||
<li>
|
||||
Aucune suppression sur demande d'un utilisateur.
|
||||
<em>(utilisez la fonction de suppression à l'envoi ou utilisez l'espace membre)</em>
|
||||
</li>
|
||||
<li>
|
||||
Toutes les données possédées seront fournies en cas de demande judiciaire.
|
||||
</li>
|
||||
<li>
|
||||
Rappel : l'administrateur (<?= _ADMINISTRATEUR_NOM_ ?>) a accès à toutes les données du service.
|
||||
</li>
|
||||
</ul>
|
||||
<div class="card-footer">
|
||||
<em>Mises à jour le 29 juin 2018 : réduction des durées de conservation des images inactives</em>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Contenus autorisés
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Toutes images de type <?= strtoupper(implode(', ', _ACCEPTED_EXTENSIONS_)) ?>.</li>
|
||||
<li>Contenus conformes à la législation française.</li>
|
||||
<li>L'administrateur du site est seul juge de la conformité d'une image aux présentes CGU. En cas de désaccord, vous pouvez le contacter via <a href="/contact.php">le formulaire de contact</a>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Contenus non autorisés
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Contenus non conformes à la législation française.</li>
|
||||
<li>Pornographie et érotisme.</li>
|
||||
<li>Scènes de violence (cadavre, torture, maltraitance, image dégradante, ...) ou d'appel à la violence.</li>
|
||||
<li>Pour information, les images peuvent être analysées par un composant d'IA dédié au service afin d'aider à leur vérification.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
Propriétés de l'hébergement
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Gratuit.</li>
|
||||
<li>Traffic illimité <em>(hors abus, auquel cas des limitations peuvent être mises en place)</em>.</li>
|
||||
<li>
|
||||
<b>Conservation :</b>
|
||||
<ul>
|
||||
<li>
|
||||
<?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jour<?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ > 1 ? 's' : '' ?> à compter de la dernière utilisation du fichier.
|
||||
</li>
|
||||
<li>
|
||||
A défaut, <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?> jour<?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ > 1 ? 's' : '' ?> après l'envoi <em>(si aucun affichage)</em>.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
Nombre d'images par compte : illimité.
|
||||
</li>
|
||||
<li>
|
||||
Les fichiers restent votre propriété.
|
||||
</li>
|
||||
<li>
|
||||
Aucune suppression sur demande d'un utilisateur. <em>(utilisez la fonction de suppression à l'envoi ou utilisez <a href="membre/connexionCompte.php">l'espace membre)</a></em>
|
||||
</li>
|
||||
<li>
|
||||
Toutes les données possédées seront fournies en cas de demande judiciaire ou de dépôt de plainte.
|
||||
</li>
|
||||
<li>
|
||||
Suppression des comptes membres qui n'ont jamais été utilisés au bout de <?= _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ ?> jour<?= _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ > 1 ? 's' : '' ?>.
|
||||
</li>
|
||||
<li>
|
||||
Rappel : <a href="contact.php">l'administrateur (<?= _ADMINISTRATEUR_NOM_ ?>)</a> a accès à toutes les données du service.
|
||||
</li>
|
||||
</ul>
|
||||
<div class="card-footer">
|
||||
<em>Mises à jour le 02 janvier 2024 : ajout de précisions sur les images non autorisées + module de catégorisation IA.</em>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
534
changelog.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,266 +24,332 @@ namespace ImageHeberg;
|
|||
require 'config/config.php';
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Historique des versions</small></h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v22">
|
||||
v2.2 - A venir
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v22" class="card-collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Envoi de plusieurs images simultanément.</li>
|
||||
<li>Glisser - déposer pour le choix des fichiers.</li>
|
||||
<li>Membres : Albums photos (création, affichage, partage).</li>
|
||||
<li>Membres : Permettre de définir une valeur par défaut pour les paramètres des images à l'envoi.</li>
|
||||
<li>Membres : Afficher les liens de partage dans l'espace membre.</li>
|
||||
<li>Expliquer les avantages pour les personnes inscrites sur le site.</li>
|
||||
</ul>
|
||||
<h1 class="mb-3"><small>Historique des versions</small></h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v2x">
|
||||
v2.x - A venir
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v2x" class="card-collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Envoi de plusieurs images simultanément.</li>
|
||||
<li>Glisser - déposer pour le choix des fichiers.</li>
|
||||
<li>Membres : Albums photos (création, affichage, partage).</li>
|
||||
<li>Membres : Permettre de définir une valeur par défaut pour les paramètres des images à l'envoi.</li>
|
||||
<li>Membres : Afficher les liens de partage dans l'espace membre.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v21">
|
||||
v21 - Février 2021
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v21" class="card-collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Migration bootstrap 4 -> 5.</li>
|
||||
<li>Suppression de jQuery.</li>
|
||||
<li>Sélection uniquement des images lors du choix du fichier sur l'ordinateur.</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v25">
|
||||
v2.5 - Janvier 2024
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v25" class="card-collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Prise en charge du format WEBP.</li>
|
||||
<li>Blocage d'accès au site pour les personnes ayant envoyé trop d'images qui ont été bloquées.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v205">
|
||||
v2.0.5 - 2020
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v205" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Migration bootstrap 3 -> 4.</li>
|
||||
<li>Utilisation de FontAwesome.</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v24">
|
||||
v2.4 - Décembre 2023
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v24" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Espace admin : renforcement des systèmes anti-abus.</li>
|
||||
<li>Meilleure gestion des GIF animés.</li>
|
||||
<li>Classification des images via IA avec nsfwjs.</li>
|
||||
<li>Amélioration des performances des requêtes dans la base de données.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v204">
|
||||
v2.0.4 - Octobre 2019
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v204" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Améliorations techniques de l'outil pour les maintenances futures.</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v23">
|
||||
v2.3 - Août 2023
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v23" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Espace admin : ajout d'une interface pour gérer les abus.</li>
|
||||
<li>Renforcement des systèmes anti-abus.</li>
|
||||
<li>Migration bootstrap 5.1 -> 5.3</li>
|
||||
<li>Migration fontawesome -> bootstrap icons</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v203">
|
||||
v2.0.3 - Octobre 2019
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v203" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Améliorations techniques pour MySQL 5.7.</li>
|
||||
<li>Améliorations techniques pour PHP7.</li>
|
||||
<li>Ajout d'un outil de validation de l'installation.</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v22">
|
||||
v2.2 - Décembre 2021
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v22" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Espace membre : ajout des miniatures des images possédées.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v202">
|
||||
v2.0.2 - Janvier 2019
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v202" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Correction d'une erreur à l'effacement des images.</li>
|
||||
<li>Migration jQuery 2 => 3</li>
|
||||
<li>Suppression de la liste des referer <em>(optimisation des affichages d'images)</em>.</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v21">
|
||||
v2.1 - Février 2021
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v21" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Migration bootstrap 4 -> 5.</li>
|
||||
<li>Suppression de jQuery.</li>
|
||||
<li>Sélection uniquement des images lors du choix du fichier sur l'ordinateur.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v201">
|
||||
v2.0.1 - Juin 2018
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v201" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Ajout d'une liste des referer</li>
|
||||
<li>Gestion dynamique des délais avant suppression des fichiers inactifs</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v205">
|
||||
v2.0.5 - 2020
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v205" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Migration bootstrap 3 -> 4.</li>
|
||||
<li>Utilisation de FontAwesome.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v20">
|
||||
v2.0 - Novembre 2016
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v20" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Réactivation de l'ensemble des fonctionnalités du site (miniatures, retournement, ...)</li>
|
||||
<li>Modèle orienté objet pour une meilleure évolutivité sur le long terme</li>
|
||||
<li>Nouveau thème graphique</li>
|
||||
<li>Admin : Refonte de l'administration</li>
|
||||
<li>Admin : création de fonctions pour nettoyer les images obsolètes</li>
|
||||
<li>Reprise du schéma de la BDD</li>
|
||||
<li>Mise en place de tests automatisés sur l'ensemble des fonctionnalités du site</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v204">
|
||||
v2.0.4 - Octobre 2019
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v204" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Améliorations techniques de l'outil pour les maintenances futures.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v19">
|
||||
v1.9 - Janvier 2014
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v19" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Passage à la programation objet</li>
|
||||
<li>Reprise, factorisation et optimisation globale du site</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v203">
|
||||
v2.0.3 - Octobre 2019
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v203" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Améliorations techniques pour MySQL 5.7.</li>
|
||||
<li>Améliorations techniques pour PHP7.</li>
|
||||
<li>Ajout d'un outil de validation de l'installation.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v127">
|
||||
v1.2.7 - 26 avril 2012
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v127" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Remise en place des options miniatures, rotation et redimensionnement</li>
|
||||
<li>Corrections de charset sur des messages d'erreur</li>
|
||||
<li>Amélioration de la protection anti-flood</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v202">
|
||||
v2.0.2 - Janvier 2019
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v202" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Correction d'une erreur à l'effacement des images.</li>
|
||||
<li>Migration jQuery 2 => 3</li>
|
||||
<li>Suppression de la liste des referer <em>(optimisation des affichages d'images)</em>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v126">
|
||||
v1.2.6 - 9 janvier 2012
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v126" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Changement de serveur internet (la vitesse d'affichage est meilleure + connectivité IPv6 !)</li>
|
||||
<li>Changement d'encodage par défaut pour les pages et le code HTML <em>(passage en UTF-8)</em></li>
|
||||
<li>Gestion de l'IPv6 dans la BDD et les statistiques</li>
|
||||
<li>Sélection du contenu des champs contenants l'url de l'image au clic</li>
|
||||
<li>Amélioration du code HTML</li>
|
||||
<li>Refonte des CSS</li>
|
||||
<li>Préparation d'un système de templates</li>
|
||||
<li>Utilisation de jQuery : box en haut de page, options cachées par défaut à l'envoi d'un fichier</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v201">
|
||||
v2.0.1 - Juin 2018
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v201" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Ajout d'une liste des referer</li>
|
||||
<li>Gestion dynamique des délais avant suppression des fichiers inactifs</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v125">
|
||||
v1.2.5 - 30 octobre 2011
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v125" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Suppression de la limite des dimensions d'images pour les utilisateurs enregistrés</li>
|
||||
<li>Ajout d'une fonction de blocage d'images + affichage d'une image d'information sur le blocage</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v20">
|
||||
v2.0 - Novembre 2016
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v20" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Réactivation de l'ensemble des fonctionnalités du site (miniatures, retournement, ...)</li>
|
||||
<li>Modèle orienté objet pour une meilleure évolutivité sur le long terme</li>
|
||||
<li>Nouveau thème graphique</li>
|
||||
<li>Admin : Refonte de l'administration</li>
|
||||
<li>Admin : création de fonctions pour nettoyer les images obsolètes</li>
|
||||
<li>Reprise du schéma de la BDD</li>
|
||||
<li>Mise en place de tests automatisés sur l'ensemble des fonctionnalités du site</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v124">
|
||||
v1.2.4 - 08 septembre 2011
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v124" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Meilleure gestion des images inexistantes (erreurs 404)</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v19">
|
||||
v1.9 - Janvier 2014
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v19" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Passage à la programation objet</li>
|
||||
<li>Reprise, factorisation et optimisation globale du site</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v123e">
|
||||
v1.2.3.e - 14 août 2011
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v123e" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Administration : suivi des requêtes SQL amélioré</li>
|
||||
<li>Finalisation de l'encodage des caractères spéciaux conformément à la norme HTML.</li>
|
||||
<li>Optimisation de la lisibilité du code source.</li>
|
||||
<li>Optimisation du temps d'éxecution du code PHP.</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v127">
|
||||
v1.2.7 - 26 avril 2012
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v127" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Remise en place des options miniatures, rotation et redimensionnement</li>
|
||||
<li>Corrections de charset sur des messages d'erreur</li>
|
||||
<li>Amélioration de la protection anti-flood</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v123d">
|
||||
v1.2.3.d - 10 août 2011
|
||||
<span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v123d" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Création du changelog.</li>
|
||||
<li>Encodage conforme à la norme HTML des caractères spéciaux.</li>
|
||||
<li>Correction d'une erreur PHP en cas d'envoi 'hack' de fichier.</li>
|
||||
<li>Amélioration de la portée des variables de language.</li>
|
||||
</ul>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v126">
|
||||
v1.2.6 - 9 janvier 2012
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v126" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Changement de serveur internet (la vitesse d'affichage est meilleure + connectivité IPv6 !)</li>
|
||||
<li>Changement d'encodage par défaut pour les pages et le code HTML <em>(passage en UTF-8)</em></li>
|
||||
<li>Gestion de l'IPv6 dans la BDD et les statistiques</li>
|
||||
<li>Sélection du contenu des champs contenants l'url de l'image au clic</li>
|
||||
<li>Amélioration du code HTML</li>
|
||||
<li>Refonte des CSS</li>
|
||||
<li>Préparation d'un système de templates</li>
|
||||
<li>Utilisation de jQuery : box en haut de page, options cachées par défaut à l'envoi d'un fichier</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v125">
|
||||
v1.2.5 - 30 octobre 2011
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v125" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Suppression de la limite des dimensions d'images pour les utilisateurs enregistrés</li>
|
||||
<li>Ajout d'une fonction de blocage d'images + affichage d'une image d'information sur le blocage</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v124">
|
||||
v1.2.4 - 08 septembre 2011
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v124" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Meilleure gestion des images inexistantes (erreurs 404)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v123e">
|
||||
v1.2.3.e - 14 août 2011
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v123e" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Administration : suivi des requêtes SQL amélioré</li>
|
||||
<li>Finalisation de l'encodage des caractères spéciaux conformément à la norme HTML.</li>
|
||||
<li>Optimisation de la lisibilité du code source.</li>
|
||||
<li>Optimisation du temps d'éxecution du code PHP.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#v123d">
|
||||
v1.2.3.d - 10 août 2011
|
||||
<span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="v123d" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Création du changelog.</li>
|
||||
<li>Encodage conforme à la norme HTML des caractères spéciaux.</li>
|
||||
<li>Correction d'une erreur PHP en cas d'envoi 'hack' de fichier.</li>
|
||||
<li>Amélioration de la portée des variables de language.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
54
classes/HelperAbuse.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
class HelperAbuse
|
||||
{
|
||||
/**
|
||||
* Retourne le nombre d'images bloquées issues du même réseau IP
|
||||
* @param string $remote_addr Adresse IP à tester
|
||||
* @return int
|
||||
*/
|
||||
public static function checkIpReputation(string $remote_addr): int
|
||||
{
|
||||
$monRetour = 0;
|
||||
|
||||
// IPv4 - Filtrer sur un /24 || IPv6 - Filtrer sur un /56
|
||||
$req = MaBDD::getInstance()->prepare(
|
||||
'SELECT COUNT(*) AS nb
|
||||
FROM images
|
||||
WHERE isBloquee = 1
|
||||
AND abuse_network = (
|
||||
IF(LOCATE(\'.\', :remote_addr) != 0,
|
||||
SUBSTRING(:remote_addr, 1, (LENGTH(:remote_addr) - LOCATE(\'.\', REVERSE(:remote_addr)))),
|
||||
SUBSTRING(HEX(INET6_ATON(:remote_addr)), 1, 14)
|
||||
)
|
||||
)'
|
||||
);
|
||||
$req->bindValue(':remote_addr', $remote_addr);
|
||||
$req->execute();
|
||||
$resultat = $req->fetch();
|
||||
if ($resultat !== false) {
|
||||
$monRetour = (int)$resultat->nb;
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre à jour la réputation des adresses IP en base
|
||||
* @return void
|
||||
*/
|
||||
public static function updateIpReputation(): void
|
||||
{
|
||||
// Compléter les données "abuse_network" (normalement déjà fait dans ImageObject::creer())
|
||||
// IPv4 - Filtrer sur un /24 || IPv6 - Filtrer sur un /56
|
||||
$req = 'UPDATE images SET abuse_network =
|
||||
IF(LOCATE(\'.\', remote_addr) != 0,
|
||||
SUBSTRING(remote_addr, 1, (LENGTH(remote_addr) - LOCATE(\'.\', REVERSE(remote_addr)))),
|
||||
SUBSTRING(HEX(INET6_ATON(remote_addr)), 1, 14)
|
||||
)
|
||||
WHERE abuse_network = \'\'';
|
||||
MaBDD::getInstance()->query($req);
|
||||
}
|
||||
}
|
404
classes/HelperAdmin.php
Normal file
|
@ -0,0 +1,404 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
/**
|
||||
* Bibliothèque d'outils pour la gestion du site en tant qu'admin
|
||||
*/
|
||||
abstract class HelperAdmin
|
||||
{
|
||||
/**
|
||||
* Liste des images n'ayant jamais été affichées et présentes sur le serveur depuis xx temps
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getNeverUsedFiles(): ArrayObject
|
||||
{
|
||||
// Toutes les images jamais affichées & envoyées il y a plus de xx jours
|
||||
$req = 'SELECT im.new_name
|
||||
FROM images im
|
||||
WHERE im.last_view = \'0000-00-00\'
|
||||
AND im.date_action < DATE_SUB(CURRENT_DATE(), INTERVAL ' . _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ . ' DAY)
|
||||
/* Préservation des fichiers des membres */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM possede po
|
||||
WHERE po.images_id = im.id
|
||||
)
|
||||
/* Préservation si miniature affichée */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM thumbnails th
|
||||
WHERE th.images_id = im.id
|
||||
AND th.last_view <> \'0000-00-00\'
|
||||
)';
|
||||
return self::queryOnNewName($req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste des images plus utilisées depuis au moins xx jours
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getUnusedFiles(): ArrayObject
|
||||
{
|
||||
// Toutes les images non affichées depuis xx jours
|
||||
$req = 'SELECT im.new_name
|
||||
FROM images im
|
||||
WHERE im.last_view < DATE_SUB(CURRENT_DATE(), INTERVAL ' . _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ . ' DAY)
|
||||
/* Non prise en compte des images jamais affichées */
|
||||
AND im.last_view <> \'0000-00-00\'
|
||||
/* Préservation des images membres */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM possede po
|
||||
WHERE po.images_id = im.id
|
||||
)
|
||||
/* Préservation si miniature affichée */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM thumbnails th
|
||||
WHERE th.images_id = im.id
|
||||
AND th.last_view > DATE_SUB(CURRENT_DATE(), INTERVAL ' . _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ . ' DAY)
|
||||
)';
|
||||
return self::queryOnNewName($req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste des comptes sans images et créés depuis au moins xx jours
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getUnusedAccounts(): ArrayObject
|
||||
{
|
||||
// Effacer les logs de connexion > 1 an
|
||||
$req = 'DELETE
|
||||
FROM login
|
||||
WHERE date_action < (NOW() - INTERVAL 1 YEAR)';
|
||||
MaBDD::getInstance()->query($req);
|
||||
|
||||
// Toutes les comptes créés et jamais utilisés depuis xx jours
|
||||
$req = 'SELECT m.id
|
||||
FROM membres m
|
||||
WHERE m.date_action < DATE_SUB(CURRENT_DATE(), INTERVAL ' . _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ . ' DAY)
|
||||
/* Préservation des comptes possédant des images */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM possede po
|
||||
WHERE po.membres_id = m.id
|
||||
)';
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
$monRetour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute l'ID du compte
|
||||
$monRetour->append($value->id);
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste de l'ensemble des images en BDD
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getAllImagesNameBDD(): ArrayObject
|
||||
{
|
||||
// Toutes les images (sauf 404 & banned)
|
||||
$req = 'SELECT md5 FROM images WHERE id > 2';
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
$monRetour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$monRetour->append($value->md5);
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste de l'ensemble des images en HDD
|
||||
* @param string $path path à analyser
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getAllImagesNameHDD(string $path): ArrayObject
|
||||
{
|
||||
$monRetour = new ArrayObject();
|
||||
|
||||
// Scanne le répertoire des images
|
||||
$scan_rep = scandir($path);
|
||||
// Pour chaque item
|
||||
foreach ($scan_rep as $item) {
|
||||
if (!in_array($item, ['.', '..', '_dummy', 'z_cache'])) {
|
||||
if (is_dir($path . $item)) {
|
||||
// Appel récursif
|
||||
if ($path . $item . '/' !== _PATH_MINIATURES_) {
|
||||
$monRetourTmp = self::getAllImagesNameHDD($path . $item . '/');
|
||||
// Parsage et récupération des sous fichiers...
|
||||
foreach ($monRetourTmp as $fichier) {
|
||||
$monRetour->append($fichier);
|
||||
}
|
||||
}
|
||||
} elseif ($item !== _IMAGE_404_ && $item !== _IMAGE_BAN_) {
|
||||
$monRetour->append($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste de l'ensemble des miniatures en BDD
|
||||
*/
|
||||
public static function getAllMiniaturesNameBDD(): ArrayObject
|
||||
{
|
||||
// Toutes les images
|
||||
$req = 'SELECT md5 FROM thumbnails';
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
|
||||
$monRetour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$monRetour->append($value->md5);
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toutes les images avec un même MD5
|
||||
* @param string $unMd5
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getImageByMd5(string $unMd5): ArrayObject
|
||||
{
|
||||
// Images avec le même MD5
|
||||
$req = MaBDD::getInstance()->prepare('SELECT new_name FROM images WHERE md5 = :md5');
|
||||
$req->bindValue(':md5', $unMd5);
|
||||
$req->execute();
|
||||
|
||||
$monRetour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($req->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$monRetour->append($value->new_name);
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toutes les images signalées
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getImagesSignalees(): ArrayObject
|
||||
{
|
||||
// Images signalées
|
||||
$req = 'SELECT new_name FROM images WHERE isSignalee = 1 and isBloquee = 0';
|
||||
return self::queryOnNewName($req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Images dont les statistiques d'affichage sont incohérentes
|
||||
* @param int $nbMax Nb affichage / jour à partir duquel on veut les images
|
||||
* @param bool $onlyOnImagesSuspectes Filtrer sur les images suspectes ?
|
||||
* @param bool $useProjection Projeter l'utilisation actuelle de l'image (potentialité de dépassement de limite ultérieur)
|
||||
* @param bool $includeApproved Inclure les images approuvées (ou signalées) ?
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getImagesTropAffichees(int $nbMax, bool $onlyOnImagesSuspectes = false, bool $useProjection = false, bool $includeApproved = false): ArrayObject
|
||||
{
|
||||
if ($onlyOnImagesSuspectes) {
|
||||
$tabNewName = [];
|
||||
foreach ((array)self::getImagesPotentiellementIndesirables() as $newName) {
|
||||
$tabNewName[] = '\'' . str_replace('\'', '', $newName) . '\'';
|
||||
}
|
||||
if (empty($tabNewName)) {
|
||||
// Mettre un placeholder vide
|
||||
$listeImagesForIn = '\'\'';
|
||||
} else {
|
||||
$listeImagesForIn = implode(',', $tabNewName);
|
||||
}
|
||||
}
|
||||
|
||||
// Images avec trop d'affichages
|
||||
if ($useProjection) {
|
||||
// Ne prendre que les images qui sont présentes depuis plus d'une heure pour limiter les faux positifs
|
||||
$req = 'SELECT im.new_name, ( ( im.nb_view_v4 + im.nb_view_v6 + (SELECT IFNULL(SUM(th.nb_view_v4 + th.nb_view_v6), 0) FROM thumbnails th where th.images_id = im.id) ) / IF(im.date_action < (NOW() - INTERVAL 1 HOUR), ( UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(im.date_action) ), -1) ) * (60 * 60 * 24 ) as nbViewPerDay';
|
||||
} else {
|
||||
$req = 'SELECT im.new_name, ( im.nb_view_v4 + im.nb_view_v6 + (SELECT IFNULL(SUM(th.nb_view_v4 + th.nb_view_v6), 0) FROM thumbnails th where th.images_id = im.id) ) / IF(DATEDIFF(NOW(), im.date_action) > 0, DATEDIFF(NOW(), im.date_action), 1) as nbViewPerDay';
|
||||
}
|
||||
$req .= ' FROM images im
|
||||
WHERE im.isBloquee = 0';
|
||||
if (!$includeApproved) {
|
||||
$req .= ' AND im.isSignalee = 0
|
||||
AND im.isApprouvee = 0';
|
||||
}
|
||||
// Filter sur certaines images
|
||||
if ($onlyOnImagesSuspectes) {
|
||||
$req .= ' AND im.new_name IN (' . $listeImagesForIn . ')';
|
||||
}
|
||||
$req .= ' HAVING nbViewPerDay > ' . $nbMax . '
|
||||
ORDER BY nbViewPerDay DESC';
|
||||
return self::queryOnNewName($req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Images dont les données sont proches d'images déjà bloquées
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getImagesPotentiellementIndesirables(): ArrayObject
|
||||
{
|
||||
// Compléter les données "abuse_network" (normalement déjà fait dans ImageObject::creer())
|
||||
HelperAbuse::updateIpReputation();
|
||||
|
||||
// Images potentiellement indésirables
|
||||
$req = 'SELECT new_name FROM (
|
||||
SELECT im.new_name, ((nb_view_v4 + nb_view_v6) / DATEDIFF(NOW(), im.date_action)) AS nbAff
|
||||
FROM images im
|
||||
LEFT JOIN possede po ON po.images_id = im.id
|
||||
WHERE im.isBloquee = 0
|
||||
AND im.isApprouvee = 0
|
||||
AND im.isSignalee = 0
|
||||
AND (
|
||||
/* Même réseau IP */
|
||||
im.abuse_network IN (SELECT DISTINCT abuse_network FROM images WHERE isBloquee = 1)
|
||||
OR (
|
||||
/* Même propriétaire */
|
||||
po.membres_id IS NOT NULL
|
||||
AND
|
||||
po.membres_id IN (SELECT DISTINCT membres_id FROM possede WHERE images_id IN (SELECT id FROM images WHERE isBloquee = 1))
|
||||
)
|
||||
OR (
|
||||
/* Même MD5 */
|
||||
im.md5 IN (SELECT DISTINCT md5 FROM images WHERE isBloquee = 1)
|
||||
)
|
||||
)
|
||||
ORDER BY nbAff DESC, im.id DESC
|
||||
) tableTmp
|
||||
LIMIT 0, 100';
|
||||
return self::queryOnNewName($req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Images dont les données sont proches d'images déjà approuvées
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function getImagesPotentiellementApprouvables(): ArrayObject
|
||||
{
|
||||
// Compléter les données "abuse_network" (normalement déjà fait dans ImageObject::creer())
|
||||
HelperAbuse::updateIpReputation();
|
||||
|
||||
// Images potentiellement approuvables
|
||||
$req = 'SELECT new_name FROM (
|
||||
SELECT im.new_name, ((nb_view_v4 + nb_view_v6) / DATEDIFF(NOW(), im.date_action)) AS nbAff
|
||||
FROM images im
|
||||
LEFT JOIN possede po ON po.images_id = im.id
|
||||
WHERE im.isBloquee = 0
|
||||
AND im.isApprouvee = 0
|
||||
AND im.isSignalee = 0
|
||||
AND (
|
||||
/* Même réseau IP */
|
||||
im.abuse_network IN (SELECT DISTINCT abuse_network FROM images WHERE isApprouvee = 1)
|
||||
OR (
|
||||
/* Même propriétaire */
|
||||
po.membres_id IS NOT NULL
|
||||
AND
|
||||
po.membres_id IN (SELECT DISTINCT membres_id FROM possede WHERE images_id IN (SELECT id FROM images WHERE isApprouvee = 1))
|
||||
)
|
||||
OR (
|
||||
/* Même MD5 */
|
||||
im.md5 IN (SELECT DISTINCT md5 FROM images WHERE isApprouvee = 1)
|
||||
)
|
||||
/*OR (
|
||||
/* Même nom originel * /
|
||||
im.old_name IN (SELECT DISTINCT old_name FROM images WHERE isApprouvee = 1)
|
||||
)*/
|
||||
)
|
||||
HAVING nbAff > ' . (_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / 2) . '
|
||||
ORDER BY nbAff DESC, im.id DESC
|
||||
) tableTmp
|
||||
LIMIT 0, 25';
|
||||
return self::queryOnNewName($req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste des réseaux avec mauvaise réputation
|
||||
* @return ArrayObject ["IP" => "count()"]
|
||||
*/
|
||||
public static function getBadNetworks(): ArrayObject
|
||||
{
|
||||
$monRetour = new ArrayObject();
|
||||
|
||||
$req = 'SELECT COUNT(*) AS nb, abuse_network FROM images WHERE isBloquee = 1 GROUP BY abuse_network';
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
$ip = $value->abuse_network;
|
||||
// Formatter les IPv6
|
||||
if (!str_contains($ip, '.')) {
|
||||
$ip = implode(':', str_split($ip, 4));
|
||||
$ip .= '::/56';
|
||||
} else {
|
||||
$ip .= '.0/24';
|
||||
}
|
||||
$monRetour->offsetSet($ip, $value->nb);
|
||||
}
|
||||
// Tri "humain"
|
||||
$monRetour->ksort(SORT_NATURAL);
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joue une requête SQL et retourne un tableau "new_name"
|
||||
* @param string $req
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function queryOnNewName(string $req): ArrayObject
|
||||
{
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
$monRetour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$monRetour->append($value->new_name);
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
}
|
214
classes/HelperImage.php
Normal file
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use Imagick;
|
||||
use ImagickException;
|
||||
|
||||
/**
|
||||
* Bibliothèque d'outils pour la gestion des images
|
||||
*/
|
||||
abstract class HelperImage
|
||||
{
|
||||
/**
|
||||
* Type de l'image
|
||||
* @param string $path chemin sur le filesystem
|
||||
* @return false|int
|
||||
*/
|
||||
public static function getType(string $path): bool|int
|
||||
{
|
||||
return exif_imagetype($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* MIME type de l'image
|
||||
* @param string $path chemin sur le filesystem
|
||||
* @return string
|
||||
*/
|
||||
public static function getMimeType(string $path): string
|
||||
{
|
||||
return image_type_to_mime_type(self::getType($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Chargement ressource PHP image
|
||||
* @param string $path
|
||||
* @return Imagick
|
||||
* @throws ImagickException
|
||||
*/
|
||||
public static function getImage(string $path): Imagick
|
||||
{
|
||||
$monImage = new Imagick();
|
||||
$monImage->readImage($path);
|
||||
|
||||
// Pour les images animeés (GIF), générer une image pour chaque frame la composant
|
||||
if (self::getType($path) === IMAGETYPE_GIF) {
|
||||
$monImage = $monImage->coalesceImages();
|
||||
}
|
||||
|
||||
return $monImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enregistrement d'une ressource PHP image
|
||||
* @param Imagick $uneImage Image à enregistrer
|
||||
* @param int $imageType type PHP de l'image
|
||||
* @param string $path chemin du fichier
|
||||
* @return bool Succès ?
|
||||
* @throws ImagickException
|
||||
*/
|
||||
public static function setImage(Imagick $uneImage, int $imageType, string $path): bool
|
||||
{
|
||||
$monRetour = false;
|
||||
|
||||
// Image animée (GIF)
|
||||
if ($imageType === IMAGETYPE_GIF) {
|
||||
$uneImage->setInterlaceScheme(Imagick::INTERLACE_GIF);
|
||||
// Pour la génération du GIF, on ne veut que les différences entre les images
|
||||
$uneImage = $uneImage->deconstructImages();
|
||||
// Suppression des commentaires & co
|
||||
$uneImage->stripImage();
|
||||
// Enregistrement de l'ensemble des images
|
||||
$monRetour = $uneImage->writeImages($path, true);
|
||||
} else {
|
||||
// Image non animée
|
||||
if ($imageType === IMAGETYPE_JPEG) {
|
||||
$uneImage->setInterlaceScheme(Imagick::INTERLACE_JPEG);
|
||||
// Pas de destruction de l'image
|
||||
$uneImage->setImageCompression(Imagick::COMPRESSION_JPEG);
|
||||
$uneImage->setImageCompressionQuality(100);
|
||||
} elseif ($imageType === IMAGETYPE_PNG) {
|
||||
$uneImage->setInterlaceScheme(Imagick::INTERLACE_PNG);
|
||||
$uneImage->setImageCompression(Imagick::COMPRESSION_LZW);
|
||||
$uneImage->setImageCompressionQuality(9);
|
||||
} elseif ($imageType === IMAGETYPE_WEBP) {
|
||||
$uneImage->setImageFormat('webp');
|
||||
$uneImage->setImageCompression(Imagick::COMPRESSION_LZW);
|
||||
$uneImage->setImageCompressionQuality(100);
|
||||
}
|
||||
// Suppression des commentaires & co
|
||||
$uneImage->stripImage();
|
||||
$monRetour = $uneImage->writeImage($path);
|
||||
}
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fourni l'extension officielle d'une ressource
|
||||
* @param string $path chemin sur le filesystem
|
||||
* @return string
|
||||
*/
|
||||
public static function getExtension(string $path): string
|
||||
{
|
||||
$ext = strtolower(image_type_to_extension(self::getType($path), false));
|
||||
if ($ext === 'jpeg') {
|
||||
// Préférence pour .jpg [filename.ext]
|
||||
$ext = 'jpg';
|
||||
}
|
||||
|
||||
return $ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Est-il possible de modifier l'image (mémoire suffisante ?)
|
||||
* @param string $path
|
||||
* @return bool Possible ?
|
||||
* @see http://www.dotsamazing.com/en/labs/phpmemorylimit
|
||||
*/
|
||||
public static function isModifiableEnMemoire(string $path): bool
|
||||
{
|
||||
$monRetour = false;
|
||||
// Nombre de canaux d'information de l'image
|
||||
$nbCanaux = 4;
|
||||
|
||||
/**
|
||||
* Information sur les canaux ?
|
||||
*/
|
||||
$imageinfo = getimagesize($path);
|
||||
// Si information sur les canaux de l'image...
|
||||
if (isset($imageinfo['channels']) && is_int($imageinfo['channels'])) {
|
||||
$nbCanaux = $imageinfo['channels'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mémoire requise :
|
||||
* (hauteur x largeur x profondeur)
|
||||
* => x 2 [imageSource + imageDest]
|
||||
* => x 1.8 [fudge factor]
|
||||
*/
|
||||
$memReq = $imageinfo[1] * $imageinfo[0] * $nbCanaux;
|
||||
$memReq *= 2;
|
||||
$memReq *= _FUDGE_FACTOR_;
|
||||
|
||||
// Est-ce possible ?
|
||||
if ($memReq < HelperSysteme::getMemoireAllouee()) {
|
||||
$monRetour = true;
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dimension maximale acceptable en mémoire pour les images
|
||||
* <br />Suppose que l'image est carrée (donc indicatif !)
|
||||
* <br /> Suppose 4 canaux dans l'image
|
||||
* @return int
|
||||
* @see isModifiableEnMemoire
|
||||
*/
|
||||
public static function getMaxDimension(): int
|
||||
{
|
||||
$memDispo = HelperSysteme::getMemoireAllouee();
|
||||
|
||||
/**
|
||||
* Mémoire requise :
|
||||
* (hauteur x largeur x profondeur)
|
||||
* => x 2 [imageSource + imageDest]
|
||||
* => x 1.8 [fudge factor]
|
||||
*/
|
||||
$dimMax = round(sqrt($memDispo / 4 / 2 / _FUDGE_FACTOR_));
|
||||
|
||||
return (int)$dimMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Est-ce une image WEBP animée ?
|
||||
* @param string $path fichier à tester
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAnimatedWebp(string $path): bool
|
||||
{
|
||||
$monRetour = false;
|
||||
|
||||
// "Note that animated WebP files cannot be read."
|
||||
// https://www.php.net/manual/en/function.imagecreatefromwebp.php
|
||||
if (self::getType($path) === IMAGETYPE_WEBP) {
|
||||
// "An animation is controlled by 'ANIM' and 'ANMF' Chunks."
|
||||
// https://developers.google.com/speed/webp/docs/riff_container?hl=en
|
||||
$headerFile = file_get_contents($path, false, null, 0, 100);
|
||||
if (stripos($headerFile, 'ANIM') !== false || stripos($headerFile, 'ANMF') !== false) {
|
||||
$monRetour = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
}
|
170
classes/HelperSysteme.php
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use ArrayObject;
|
||||
use Imagick;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
* Bibliothèque d'outils pour la gestion du système
|
||||
*/
|
||||
abstract class HelperSysteme
|
||||
{
|
||||
/**
|
||||
* Taille mémoire maximale autorisée
|
||||
* @see http://php.net/manual/fr/function.ini-get.php
|
||||
* @return int
|
||||
*/
|
||||
public static function getMemoireAllouee(): int
|
||||
{
|
||||
// Récupération de la valeur du php.ini
|
||||
$valBrute = trim(ini_get('memory_limit'));
|
||||
// memory_limit=0 / -1 est possible
|
||||
if ($valBrute <= 0) {
|
||||
// Arbitrairement limite à 2Go
|
||||
$valBrute = '2G';
|
||||
}
|
||||
|
||||
// Gestion de l'unité multiplicatrice...
|
||||
$unite = strtolower(substr($valBrute, -1));
|
||||
$monRetour = (int)substr($valBrute, 0, -1);
|
||||
switch ($unite) {
|
||||
case 'g':
|
||||
$monRetour *= 1024;
|
||||
// no break
|
||||
case 'm':
|
||||
$monRetour *= 1024;
|
||||
// no break
|
||||
case 'k':
|
||||
$monRetour *= 1024;
|
||||
// no break
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version de PHP
|
||||
* @return string
|
||||
*/
|
||||
public static function getPhpVersion(): string
|
||||
{
|
||||
return PHP_VERSION . ' - ' . PHP_OS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version de Imagick
|
||||
* @return string
|
||||
*/
|
||||
public static function getImagickVersion(): string
|
||||
{
|
||||
return Imagick::getVersion()['versionString'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Version de MySQL
|
||||
* @return string
|
||||
*/
|
||||
public static function getMysqlVersion(): string
|
||||
{
|
||||
// Exécution de la requête
|
||||
return MaBDD::getInstance()->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Headers HTTP status code
|
||||
* @param string $url URL à tester
|
||||
* @return string retour HTTP
|
||||
*/
|
||||
public static function getStatusHTTP(string $url): string
|
||||
{
|
||||
$classe = 'danger';
|
||||
$fa = 'exclamation-circle';
|
||||
|
||||
// On regarde ce que ça donne
|
||||
$resultat = get_headers($url);
|
||||
|
||||
// Est-ce le résultat attendu ?
|
||||
if (stripos($resultat[0], 'Forbidden')) {
|
||||
$classe = 'success';
|
||||
$fa = 'check';
|
||||
}
|
||||
// Mise en forme du résultat
|
||||
return '<span class="bi-' . $fa . ' text-' . $classe . '"> ' . $resultat[0] . '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie de manière récursive l'écriture dans un dossier
|
||||
* @param string $folder Path du dossier parent
|
||||
* @return ArrayObject
|
||||
*/
|
||||
public static function isRecursivelyWritable(string $folder): ArrayObject
|
||||
{
|
||||
// On évite le // dans le path... (estéthique)
|
||||
if (str_ends_with($folder, '/')) {
|
||||
$folder = substr($folder, 0, -1);
|
||||
}
|
||||
$monRetour = new ArrayObject();
|
||||
|
||||
if (is_writable($folder)) {
|
||||
$monRetour->append('<span class="bi-check text-success"> ' . $folder . '</span>');
|
||||
} else {
|
||||
$monRetour->append('<span class="bi-exclamation-circle text-danger"> ' . $folder . '</span>');
|
||||
}
|
||||
|
||||
// Dossiers enfants
|
||||
$objects = glob($folder . '/*', GLOB_ONLYDIR);
|
||||
foreach ($objects as $object) {
|
||||
// Je vérifie si les dossiers enfants sont écrivables
|
||||
$sousRetour = self::isRecursivelyWritable($object);
|
||||
// Gestion de l'itération...
|
||||
foreach ($sousRetour as $unRetour) {
|
||||
$monRetour->append($unRetour);
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Volume des images
|
||||
* @return float
|
||||
*/
|
||||
public static function getHDDUsage(): float
|
||||
{
|
||||
// Poids de l'ensemble des images
|
||||
$req = 'SELECT SUM(im.size) AS images, (
|
||||
SELECT SUM(th.size)
|
||||
FROM thumbnails th
|
||||
) AS miniatures
|
||||
FROM images im';
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
// Récupération de la valeur
|
||||
$value = $resultat->fetch();
|
||||
|
||||
return round(($value->images + $value->miniatures) / (1024 * 1024 * 1024));
|
||||
}
|
||||
}
|
47
classes/ImageHebergException.class.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Exception custom à l'application
|
||||
*/
|
||||
class ImageHebergException extends Exception
|
||||
{
|
||||
/**
|
||||
* Définir les champs custom de l'exception
|
||||
*
|
||||
* @param string $message Message d'erreur
|
||||
* @param int $code Code de l'exception
|
||||
* @param string $file Fichier où l'erreur à eu lieu
|
||||
* @param int $line Line concernée
|
||||
* @return void
|
||||
*/
|
||||
public function define(string $message, int $code, string $file, int $line): void
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->code = $code;
|
||||
$this->file = $file;
|
||||
$this->line = $line;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,6 +21,9 @@
|
|||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use ArrayObject;
|
||||
use Exception;
|
||||
use ImagickException;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
|
@ -28,150 +31,195 @@ use PDO;
|
|||
*/
|
||||
class ImageObject extends RessourceObject implements RessourceInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
* @param string $newName nom de l'image
|
||||
* @param string $value Identifiant image-heberg
|
||||
* @param string $fromField Champ à utiliser en BDD
|
||||
* @throws ImageHebergException
|
||||
*/
|
||||
public function __construct($newName = false)
|
||||
public function __construct(string $value = '', string $fromField = RessourceObject::SEARCH_BY_NAME)
|
||||
{
|
||||
// Définition du type pour le RessourceObject
|
||||
$this->setType(RessourceObject::TYPE_IMAGE);
|
||||
|
||||
// Si on me donne un ID d'image, je charge l'objet
|
||||
if ($newName) {
|
||||
if (!$this->charger($newName)) {
|
||||
// Envoi d'une exception si l'image n'existe pas
|
||||
throw new Exception('Image ' . $newName . ' inexistante');
|
||||
}
|
||||
// Faut-il charger l'objet ?
|
||||
if ($value !== '' && !$this->charger($value, $fromField)) {
|
||||
// Envoi d'une exception si l'image n'existe pas
|
||||
throw new ImageHebergException('Image ' . $value . ' inexistante (' . $fromField . ')');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function charger($newName)
|
||||
public function charger(string $value, string $fromField = RessourceObject::SEARCH_BY_NAME): bool
|
||||
{
|
||||
// Retour
|
||||
$monRetour = false;
|
||||
// Charger les informations depuis la BDD
|
||||
$this->chargerFromBdd([$value], $fromField);
|
||||
|
||||
// Je vais chercher les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare("SELECT * FROM images WHERE new_name = :newName");
|
||||
$req->bindValue(':newName', $newName, PDO::PARAM_STR);
|
||||
$req->execute();
|
||||
// Gestion du retour
|
||||
return ($this->getId() !== 0);
|
||||
}
|
||||
|
||||
// J'éclate les informations
|
||||
$resultat = $req->fetch();
|
||||
if ($resultat !== false) {
|
||||
$this->setId($resultat->id);
|
||||
$this->setIpEnvoi($resultat->ip_envoi);
|
||||
$this->setDateEnvoi($resultat->date_envoi);
|
||||
$this->setNomOriginal($resultat->old_name);
|
||||
// Permet l'effacement des fichiers non enregistrés en BDD
|
||||
$this->setNomNouveau($newName);
|
||||
$this->setPoids($resultat->size);
|
||||
$this->setHauteur($resultat->height);
|
||||
$this->setLargeur($resultat->width);
|
||||
$this->setLastView($resultat->last_view);
|
||||
$this->setNbViewIPv4($resultat->nb_view_v4);
|
||||
$this->setNbViewIPv6($resultat->nb_view_v6);
|
||||
$this->setMd5($resultat->md5);
|
||||
$this->setBloquee($resultat->isBloquee);
|
||||
$this->setSignalee($resultat->isSignalee);
|
||||
/**
|
||||
* Charger des images en masse
|
||||
* @param ArrayObject $values Valeur du champ $fromField
|
||||
* @param string $fromField Nom du champ à utiliser en BDD pour identifier les images
|
||||
* @param bool $orderByIdAsc Trier les résultats par ID ASC ?
|
||||
* @return array
|
||||
*/
|
||||
public static function chargerMultiple(ArrayObject $values, string $fromField, bool $orderByIdAsc = true): array
|
||||
{
|
||||
$monRetour = [];
|
||||
|
||||
// Gestion du retour
|
||||
$monRetour = true;
|
||||
if (count($values) > 0) {
|
||||
$monRetour = (new ImageObject())->chargerFromBdd((array)$values, $fromField, false, $orderByIdAsc);
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Charger des images depuis la BDD
|
||||
* @param array $values Valeurs du champ $fromField
|
||||
* @param string $fromField Nom du champ à utiliser en BDD pour identifier les images
|
||||
* @param bool $saveOnCurrentObject Enregistrer les résultats dans l'objet courant ou dans un tableau ?
|
||||
* @param bool $orderByIdAsc Trier les résultats par ID ASC ?
|
||||
* @return array
|
||||
*/
|
||||
public function sauver()
|
||||
private function chargerFromBdd(array $values, string $fromField, bool $saveOnCurrentObject = true, bool $orderByIdAsc = true): array
|
||||
{
|
||||
$monRetour = [];
|
||||
|
||||
// Génération des placeholders
|
||||
$placeHolders = str_repeat('?,', count($values) - 1) . '?';
|
||||
// Je vais chercher les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare('SELECT *, (SELECT COUNT(*) FROM images im2 WHERE im2.isBloquee = 1 AND im2.abuse_network = images.abuse_network) AS reputation FROM images LEFT JOIN possede on images.id = possede.images_id WHERE ' . $fromField . ' IN (' . $placeHolders . ') ORDER BY images.id ' . ($orderByIdAsc ? 'ASC' : 'DESC'));
|
||||
$req->execute($values);
|
||||
|
||||
// Traitement des résultats
|
||||
foreach ($req->fetchAll() as $resultat) {
|
||||
if ($saveOnCurrentObject) {
|
||||
$varName = 'this';
|
||||
} else {
|
||||
$varName = 'uneImage';
|
||||
unset(${$varName});
|
||||
${$varName} = new ImageObject();
|
||||
}
|
||||
${$varName}->setId($resultat->id);
|
||||
${$varName}->setIpEnvoi($resultat->remote_addr);
|
||||
${$varName}->setDateEnvoi($resultat->date_action);
|
||||
${$varName}->setNomOriginal($resultat->old_name);
|
||||
${$varName}->setNomNouveau($resultat->new_name);
|
||||
${$varName}->setPoids($resultat->size);
|
||||
${$varName}->setHauteur($resultat->height);
|
||||
${$varName}->setLargeur($resultat->width);
|
||||
${$varName}->setLastView($resultat->last_view);
|
||||
${$varName}->setNbViewIPv4($resultat->nb_view_v4);
|
||||
${$varName}->setNbViewIPv6($resultat->nb_view_v6);
|
||||
${$varName}->setMd5($resultat->md5);
|
||||
${$varName}->setBloquee($resultat->isBloquee);
|
||||
${$varName}->setSignalee($resultat->isSignalee);
|
||||
${$varName}->setApprouvee($resultat->isApprouvee);
|
||||
${$varName}->setIdProprietaire($resultat->membres_id);
|
||||
${$varName}->setSuspecte(($resultat->reputation > 0));
|
||||
|
||||
if (!$saveOnCurrentObject) {
|
||||
// Gestion du retour
|
||||
$monRetour[] = ${$varName};
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
public function sauver(): void
|
||||
{
|
||||
// J'enregistre les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare("UPDATE images SET ip_envoi = :ipEnvoi, date_envoi = :dateEnvoi, old_name = :oldName, new_name = :newName, size = :size, height = :height, width = :width, last_view = :lastView, nb_view_v4 = :nbViewV4, nb_view_v6 = :nbViewV6, md5 = :md5, isBloquee = :isBloquee, isSignalee = :isSignalee WHERE id = :id");
|
||||
$req->bindValue(':ipEnvoi', $this->getIpEnvoi(), PDO::PARAM_STR);
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE images SET remote_addr = :ipEnvoi, date_action = :dateEnvoi, old_name = :oldName, new_name = :newName, size = :size, height = :height, width = :width, last_view = :lastView, nb_view_v4 = :nbViewV4, nb_view_v6 = :nbViewV6, md5 = :md5, isBloquee = :isBloquee, isSignalee = :isSignalee, isApprouvee = :isApprouvee WHERE id = :id');
|
||||
$req->bindValue(':ipEnvoi', $this->getIpEnvoi());
|
||||
$req->bindValue(':dateEnvoi', $this->getDateEnvoiBrute());
|
||||
$req->bindValue(':oldName', $this->getNomOriginal(), PDO::PARAM_STR);
|
||||
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STR);
|
||||
$req->bindValue(':oldName', $this->getNomOriginal());
|
||||
$req->bindValue(':newName', $this->getNomNouveau());
|
||||
$req->bindValue(':size', $this->getPoids(), PDO::PARAM_INT);
|
||||
$req->bindValue(':height', $this->getHauteur(), PDO::PARAM_INT);
|
||||
$req->bindValue(':width', $this->getLargeur(), PDO::PARAM_INT);
|
||||
$req->bindValue(':lastView', $this->getLastView());
|
||||
$req->bindValue(':nbViewV4', $this->getNbViewIPv4(), PDO::PARAM_INT);
|
||||
$req->bindValue(':nbViewV6', $this->getNbViewIPv6(), PDO::PARAM_INT);
|
||||
$req->bindValue(':md5', $this->getMd5(), PDO::PARAM_STR);
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
$req->bindValue(':isBloquee', $this->isBloquee(), PDO::PARAM_INT);
|
||||
$req->bindValue(':isSignalee', $this->isSignalee(), PDO::PARAM_INT);
|
||||
$req->bindValue(':isApprouvee', $this->isApprouvee(), PDO::PARAM_INT);
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
|
||||
$req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Récupérer les ID des images des miniatures associées
|
||||
* @param bool $onlyPreview Uniquement les miniatures d'aperçu dans l'espace membre ?
|
||||
* @return ArrayObject new_name en BDD des miniatures
|
||||
*/
|
||||
public function supprimer()
|
||||
public function getMiniatures(bool $onlyPreview = false): ArrayObject
|
||||
{
|
||||
$monRetour = true;
|
||||
$monRetour = new ArrayObject();
|
||||
|
||||
/**
|
||||
* Suppression de la ou les miniatures
|
||||
*/
|
||||
// Chargement des miniatures
|
||||
$req = MaBDD::getInstance()->prepare("SELECT new_name FROM thumbnails where id_image = :idImage");
|
||||
$req->bindValue(':idImage', $this->getId(), PDO::PARAM_INT);
|
||||
$query = 'SELECT new_name FROM thumbnails WHERE images_id = :imagesId';
|
||||
if ($onlyPreview) {
|
||||
$query .= ' AND is_preview = 1';
|
||||
}
|
||||
|
||||
$req = MaBDD::getInstance()->prepare($query);
|
||||
$req->bindValue(':imagesId', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
|
||||
// Je passe toutes les lignes de résultat
|
||||
foreach ($req->fetchAll() as $value) {
|
||||
// Chargement de la miniature
|
||||
$maMiniature = new MiniatureObject($value->new_name);
|
||||
// Suppression
|
||||
$maMiniature->supprimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression de l'affectation
|
||||
*/
|
||||
if ($monRetour) {
|
||||
$req = MaBDD::getInstance()->prepare("DELETE FROM possede WHERE image_id = :imageId");
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':imageId', $this->getId(), PDO::PARAM_INT);
|
||||
$monRetour = $req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression de l'image en BDD
|
||||
*/
|
||||
if ($monRetour) {
|
||||
$req = MaBDD::getInstance()->prepare("DELETE FROM images WHERE id = :id");
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
$monRetour = $req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression du HDD
|
||||
*/
|
||||
if ($monRetour) {
|
||||
// Plus aucune image n'utilise le fichier (BDD déjà mise à jour !)
|
||||
if ($this->getNbDoublons() == 0) {
|
||||
// Je supprime l'image sur le HDD
|
||||
$monRetour = unlink($this->getPathMd5());
|
||||
}
|
||||
// Nom du fichier
|
||||
$monRetour->append($value->new_name);
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws ImageHebergException
|
||||
*/
|
||||
public function creer()
|
||||
public function supprimer(): void
|
||||
{
|
||||
/**
|
||||
* Suppression de la ou les miniatures
|
||||
*/
|
||||
// Je passe toutes les lignes de résultat
|
||||
foreach ($this->getMiniatures() as $new_name) {
|
||||
// Chargement de la miniature
|
||||
$maMiniature = new MiniatureObject($new_name);
|
||||
// Suppression
|
||||
$maMiniature->supprimer();
|
||||
}
|
||||
|
||||
// Suppresion de l'affectation en BDD
|
||||
$req = MaBDD::getInstance()->prepare('DELETE FROM possede WHERE images_id = :imagesId');
|
||||
$req->bindValue(':imagesId', $this->getId(), PDO::PARAM_INT);
|
||||
if ($req->execute()) {
|
||||
// Suppresion de l'image en BDD
|
||||
$req = MaBDD::getInstance()->prepare('DELETE FROM images WHERE id = :id');
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
// Si plus aucune image n'utilise le fichier => supprimer l'image sur le HDD
|
||||
if (
|
||||
$req->execute()
|
||||
&& $this->getNbUsages() === 0
|
||||
&& is_file($this->getPathMd5())
|
||||
) {
|
||||
unlink($this->getPathMd5());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ImagickException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function creer(): bool
|
||||
{
|
||||
// Retour
|
||||
$monRetour = true;
|
||||
|
@ -194,15 +242,29 @@ class ImageObject extends RessourceObject implements RessourceInterface
|
|||
// On enregistre le nom
|
||||
$this->setNomNouveau($new_name);
|
||||
|
||||
// PHP ne gère pas les images WebP animée -> ne pas faire de traitements
|
||||
if (!HelperImage::isAnimatedWebp($this->getPathTemp())) {
|
||||
// Optimiser l'image (permettra de comparer son hash avec celles déjà stockées)
|
||||
HelperImage::setImage(HelperImage::getImage($this->getPathTemp()), HelperImage::getType($this->getPathTemp()), $this->getPathTemp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Déplacement du fichier
|
||||
*/
|
||||
// Vérification de la non existence du fichier
|
||||
if ($this->getNbDoublons() == 0) {
|
||||
// Image inconnue : optimisation de sa taille
|
||||
$monRetour = Outils::setImage(Outils::getImage($this->getPathTemp()), Outils::getType($this->getPathTemp()), $this->getPathTemp());
|
||||
if ($this->getNbUsages() === 0) {
|
||||
// Copie du fichier vers l'emplacement de stockage
|
||||
copy($this->getPathTemp(), $this->getPathMd5());
|
||||
// Ne peut pas être fait avant car le MD5 n'est pas encore connu
|
||||
$monRetour = copy($this->getPathTemp(), $this->getPathMd5());
|
||||
} else {
|
||||
// Ce MD5 est-il déjà bloqué pour une autre image ?
|
||||
$req = MaBDD::getInstance()->prepare('SELECT MAX(isBloquee) AS isBloquee FROM images WHERE md5 = :md5');
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
$req->execute();
|
||||
$values = $req->fetch();
|
||||
if ($values !== false) {
|
||||
$this->setBloquee((bool)$values->isBloquee);
|
||||
}
|
||||
}
|
||||
|
||||
// Ssi copie du fichier réussie
|
||||
|
@ -224,15 +286,16 @@ class ImageObject extends RessourceObject implements RessourceInterface
|
|||
/**
|
||||
* Création en BDD
|
||||
*/
|
||||
$req = MaBDD::getInstance()->prepare("INSERT INTO images (ip_envoi, date_envoi, old_name, new_name, size, height, width, md5) VALUES (:ipEnvoi, NOW(), :oldName, :newName, :size, :height, :width, :md5)");
|
||||
$req->bindValue(':ipEnvoi', $this->getIpEnvoi(), PDO::PARAM_STR);
|
||||
$req = MaBDD::getInstance()->prepare('INSERT INTO images (remote_addr, date_action, old_name, new_name, size, height, width, md5, isBloquee) VALUES (:ipEnvoi, NOW(), :oldName, :newName, :size, :height, :width, :md5, :isBloquee)');
|
||||
$req->bindValue(':ipEnvoi', $this->getIpEnvoi());
|
||||
// Date : NOW()
|
||||
$req->bindValue(':oldName', $this->getNomOriginal(), PDO::PARAM_STR);
|
||||
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STR);
|
||||
$req->bindValue(':oldName', $this->getNomOriginal());
|
||||
$req->bindValue(':newName', $this->getNomNouveau());
|
||||
$req->bindValue(':size', $this->getPoids(), PDO::PARAM_INT);
|
||||
$req->bindValue(':height', $this->getHauteur(), PDO::PARAM_INT);
|
||||
$req->bindValue(':width', $this->getLargeur(), PDO::PARAM_INT);
|
||||
$req->bindValue(':md5', $this->getMd5(), PDO::PARAM_STR);
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
$req->bindValue(':isBloquee', $this->isBloquee());
|
||||
|
||||
if (!$req->execute()) {
|
||||
// Gestion de l'erreur d'insertion en BDD
|
||||
|
@ -243,6 +306,67 @@ class ImageObject extends RessourceObject implements RessourceInterface
|
|||
*/
|
||||
$idEnregistrement = MaBDD::getInstance()->lastInsertId();
|
||||
$this->setId($idEnregistrement);
|
||||
// Définir les informations relatives au réseau utilisé (anti abus)
|
||||
HelperAbuse::updateIpReputation();
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bloquer une image en BDD
|
||||
* Effet contaminant sur les autres images partagant le même MD5
|
||||
*/
|
||||
public function bloquer(): void
|
||||
{
|
||||
// J'enregistre les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE images SET isBloquee = 1, isApprouvee = 0 WHERE md5 = :md5');
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
|
||||
$req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Approuver une image en BDD
|
||||
* Effet contaminant sur les autres images partagant le même MD5
|
||||
*/
|
||||
public function approuver(): void
|
||||
{
|
||||
// J'enregistre les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE images SET isBloquee = 0, isSignalee = 0, isApprouvee = 1 WHERE md5 = :md5');
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
|
||||
$req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Nombre d'appels IPv4 & IPv6
|
||||
* @return int
|
||||
*/
|
||||
public function getNbViewTotal(): int
|
||||
{
|
||||
return parent::getNbViewTotal() + $this->getNbViewMiniatures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupérer le total d'affichage des miniatures
|
||||
* @return int
|
||||
*/
|
||||
public function getNbViewMiniatures(): int
|
||||
{
|
||||
$monRetour = 0;
|
||||
|
||||
// Chargement des miniatures
|
||||
$query = 'SELECT SUM(nb_view_v4 + nb_view_v6) as total FROM thumbnails WHERE images_id = :imagesId';
|
||||
$req = MaBDD::getInstance()->prepare($query);
|
||||
$req->bindValue(':imagesId', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
|
||||
// Je passe toutes les lignes de résultat
|
||||
foreach ($req->fetchAll() as $value) {
|
||||
if (!is_null($value->total)) {
|
||||
$monRetour = $value->total;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -22,6 +22,7 @@
|
|||
namespace ImageHeberg;
|
||||
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
|
||||
/**
|
||||
* Lien vers la BDD
|
||||
|
@ -31,9 +32,9 @@ use PDO;
|
|||
class MaBDD
|
||||
{
|
||||
// PDO
|
||||
private $maBDD = null;
|
||||
private PDO $maBDD;
|
||||
// Instance de la classe
|
||||
private static $monInstance = null;
|
||||
private static ?MaBDD $monInstance = null;
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
|
@ -47,9 +48,9 @@ class MaBDD
|
|||
|
||||
/**
|
||||
* Crée & renvoi l'objet d'instance
|
||||
* @return PDO
|
||||
* @return MaBDD
|
||||
*/
|
||||
public static function getInstance()
|
||||
public static function getInstance(): MaBDD
|
||||
{
|
||||
// Si pas de connexion active, en crée une
|
||||
if (is_null(self::$monInstance)) {
|
||||
|
@ -61,9 +62,9 @@ class MaBDD
|
|||
/**
|
||||
* PDO::query
|
||||
* @param string $query
|
||||
* @return type
|
||||
* @return false|PDOStatement
|
||||
*/
|
||||
public function query($query)
|
||||
public function query(string $query): bool|PDOStatement
|
||||
{
|
||||
return $this->maBDD->query($query);
|
||||
}
|
||||
|
@ -71,18 +72,18 @@ class MaBDD
|
|||
/**
|
||||
* PDO::prepare
|
||||
* @param string $query
|
||||
* @return type
|
||||
* @return false|PDOStatement
|
||||
*/
|
||||
public function prepare($query)
|
||||
public function prepare(string $query): bool|PDOStatement
|
||||
{
|
||||
return $this->maBDD->prepare($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* PDO::lastInsertId
|
||||
* @return type
|
||||
* @return string
|
||||
*/
|
||||
public function lastInsertId()
|
||||
public function lastInsertId(): string
|
||||
{
|
||||
return $this->maBDD->lastInsertId();
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ class MaBDD
|
|||
/**
|
||||
* Fermeture du PDO
|
||||
*/
|
||||
public static function close()
|
||||
public static function close(): void
|
||||
{
|
||||
self::$monInstance = null;
|
||||
}
|
||||
|
@ -98,9 +99,9 @@ class MaBDD
|
|||
/**
|
||||
* PDO::getAttribute
|
||||
* @param int $attribute
|
||||
* @return type
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute($attribute)
|
||||
public function getAttribute(int $attribute): mixed
|
||||
{
|
||||
return $this->maBDD->getAttribute($attribute);
|
||||
}
|
||||
|
|
|
@ -1,309 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use PDO;
|
||||
use ArrayObject;
|
||||
|
||||
/**
|
||||
* Les méthodes "génériques"
|
||||
*
|
||||
* @author anael
|
||||
*/
|
||||
class MetaObject
|
||||
{
|
||||
|
||||
/**
|
||||
* Liste des images n'ayant jamais été affichées et présentes sur le serveur depuis xx temps
|
||||
* @return \ArrayObject
|
||||
*/
|
||||
public static function getNeverUsedFiles()
|
||||
{
|
||||
// Toutes les images jamais affichées & envoyées il y a plus de xx jours
|
||||
$req = "SELECT im.new_name
|
||||
FROM images im
|
||||
WHERE im.last_view IS NULL
|
||||
AND im.date_envoi < DATE_SUB(CURRENT_DATE(), INTERVAL " . _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ . " DAY)
|
||||
/* Préservation des fichiers des membres */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM possede po
|
||||
WHERE po.image_id = im.id
|
||||
)
|
||||
/* Préservation si miniature affichée */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM thumbnails th
|
||||
WHERE th.id_image = im.id
|
||||
AND th.last_view IS NOT NULL
|
||||
)
|
||||
";
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
$retour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$retour->append($value->new_name);
|
||||
}
|
||||
|
||||
return $retour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste des images plus utilisées depuis au moins xx jours
|
||||
* @return \ArrayObject
|
||||
*/
|
||||
public static function getUnusedFiles()
|
||||
{
|
||||
// Toutes les images non affichées depuis xx jours
|
||||
$req = "SELECT im.new_name
|
||||
FROM images im
|
||||
WHERE im.last_view < DATE_SUB(CURRENT_DATE(), INTERVAL " . _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ . " DAY)
|
||||
/* Non prise en compte des images jamais affichées */
|
||||
AND im.last_view IS NOT NULL
|
||||
/* Préservation des images membres */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM possede po
|
||||
WHERE po.image_id = im.id
|
||||
)
|
||||
/* Préservation si miniature affichée */
|
||||
AND 0 = (
|
||||
SELECT COUNT(*)
|
||||
FROM thumbnails th
|
||||
WHERE th.id_image = im.id
|
||||
AND th.last_view > DATE_SUB(CURRENT_DATE(), INTERVAL " . _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ . " DAY)
|
||||
)";
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
|
||||
$retour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$retour->append($value->new_name);
|
||||
}
|
||||
|
||||
return $retour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste de l'ensemble des images en BDD
|
||||
* @return \ArrayObject
|
||||
*/
|
||||
public static function getAllImagesNameBDD()
|
||||
{
|
||||
// Toutes les images (sauf 404 & banned)
|
||||
$req = "SELECT md5 FROM images WHERE id > 2";
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
$retour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$retour->append($value->md5);
|
||||
}
|
||||
|
||||
return $retour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste de l'ensemble des images en HDD
|
||||
* @param type $path path à analyser
|
||||
* @return \ArrayObject
|
||||
*/
|
||||
public static function getAllImagesNameHDD($path)
|
||||
{
|
||||
$monRetour = new ArrayObject();
|
||||
|
||||
// Scanne le répertoire des images
|
||||
$scan_rep = scandir($path);
|
||||
// Pour chaque item
|
||||
foreach ($scan_rep as $item) {
|
||||
if ($item !== '.' && $item !== '..' && $item !== '_dummy') {
|
||||
if (is_dir($path . $item)) {
|
||||
// Appel récursif
|
||||
if ($path . $item . '/' !== _PATH_MINIATURES_) {
|
||||
$monRetourTmp = self::getAllImagesNameHDD($path . $item . '/');
|
||||
// Parsage et récupération des sous fichiers...
|
||||
foreach ($monRetourTmp as $fichier) {
|
||||
$monRetour->append($fichier);
|
||||
}
|
||||
}
|
||||
} elseif ($item !== _IMAGE_404_ && $item !== _IMAGE_BAN_) {
|
||||
$monRetour->append($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste de l'ensemble des miniatures en BDD
|
||||
*/
|
||||
public static function getAllMiniaturesNameBDD()
|
||||
{
|
||||
// Toutes les images
|
||||
$req = "SELECT thumbnails.md5 FROM images, thumbnails WHERE images.id = thumbnails.id";
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
|
||||
$retour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($resultat->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$retour->append($value->md5);
|
||||
}
|
||||
|
||||
return $retour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Volume des images
|
||||
* @return int
|
||||
*/
|
||||
public static function getHDDUsage()
|
||||
{
|
||||
// Poids de l'ensemble des images
|
||||
$req = "SELECT SUM(im.size) AS images, (
|
||||
SELECT SUM(th.size)
|
||||
FROM thumbnails th
|
||||
) AS miniatures
|
||||
FROM images im";
|
||||
|
||||
// Exécution de la requête
|
||||
$resultat = MaBDD::getInstance()->query($req);
|
||||
|
||||
// Récupération de la valeur
|
||||
$value = $resultat->fetch();
|
||||
|
||||
$retour = round(($value->images + $value->miniatures) / (1024 * 1024 * 1024));
|
||||
|
||||
return $retour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version de PHP
|
||||
* @return string
|
||||
*/
|
||||
public static function getPhpVersion()
|
||||
{
|
||||
$retour = PHP_VERSION . " - " . PHP_OS;
|
||||
|
||||
return $retour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version de MySQL
|
||||
* @return string
|
||||
*/
|
||||
public static function getMysqlVersion()
|
||||
{
|
||||
// Exécution de la requête
|
||||
$retour = MaBDD::getInstance()->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
|
||||
return $retour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Headers HTTP status code
|
||||
* @param string $url URL à tester
|
||||
* @return string retour HTTP
|
||||
*/
|
||||
public static function getStatusHTTP($url)
|
||||
{
|
||||
$retour = get_headers($url);
|
||||
|
||||
return $retour[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie de manière récursive l'écriture dans un dossier
|
||||
* @param string $folder Path du dossier parent
|
||||
* @return \ArrayObject
|
||||
*/
|
||||
public static function isRecursivelyWritable($folder)
|
||||
{
|
||||
// On évite le // dans le path... (estéthique)
|
||||
if (substr($folder, -1) === "/") {
|
||||
$folder = substr($folder, 0, -1);
|
||||
}
|
||||
$monRetour = new ArrayObject();
|
||||
|
||||
if (is_writable($folder)) {
|
||||
$monRetour->append("OK - $folder");
|
||||
} else {
|
||||
$monRetour->append("KO - $folder");
|
||||
}
|
||||
|
||||
// Enfants...
|
||||
$objects = scandir($folder);
|
||||
foreach ($objects as $object) {
|
||||
// Perfs : élimination de tous les noms contenant un . (fichier.ext)
|
||||
if (strpos($object, ".") === false) {
|
||||
$pathObject = $folder . "/" . $object;
|
||||
// . & .. n'arrivent pas ici...
|
||||
if (is_dir($pathObject)) {
|
||||
$sousRetour = self::isRecursivelyWritable($pathObject);
|
||||
// Gestion de l'itération...
|
||||
foreach ($sousRetour as $unRetour) {
|
||||
$monRetour->append($unRetour);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toutes les images avec un même MD5
|
||||
* @param string $unMd5
|
||||
* @return \ArrayObject
|
||||
*/
|
||||
public static function getImageByMd5($unMd5)
|
||||
{
|
||||
// Images avec le même MD5
|
||||
$req = MaBDD::getInstance()->prepare("SELECT new_name FROM images WHERE md5 = :md5");
|
||||
$req->bindValue(':md5', $unMd5, PDO::PARAM_STR);
|
||||
$req->execute();
|
||||
|
||||
$retour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($req->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$retour->append($value->new_name);
|
||||
}
|
||||
|
||||
return $retour;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use Exception;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
|
@ -28,37 +29,34 @@ use PDO;
|
|||
*/
|
||||
class MiniatureObject extends RessourceObject implements RessourceInterface
|
||||
{
|
||||
private $idImage;
|
||||
private int $idImage;
|
||||
private bool $isPreview = false;
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
* @param string $newName newName de l'image maître
|
||||
* @param string $value Identifiant image-heberg
|
||||
* @param string $fromField Champ à utiliser en BDD
|
||||
* @throws ImageHebergException
|
||||
*/
|
||||
public function __construct($newName = false)
|
||||
public function __construct(string $value = '', string $fromField = RessourceObject::SEARCH_BY_NAME)
|
||||
{
|
||||
// Définition du type pour le RessourceObject
|
||||
$this->setType(RessourceObject::TYPE_MINIATURE);
|
||||
|
||||
// Si on me donne un newName d'image, je charge l'objet
|
||||
if ($newName) {
|
||||
if (!$this->charger($newName)) {
|
||||
// Envoi d'une exception si l'image n'existe pas
|
||||
throw new Exception('Miniature ' . $newName . ' inexistante');
|
||||
}
|
||||
// Faut-il charger l'objet ?
|
||||
if ($value !== '' && !$this->charger($value, $fromField)) {
|
||||
// Envoi d'une exception si l'image n'existe pas
|
||||
throw new ImageHebergException('Miniature ' . $value . ' inexistante - ' . $fromField);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function charger($newName)
|
||||
public function charger(string $value, string $fromField = RessourceObject::SEARCH_BY_NAME): bool
|
||||
{
|
||||
$monRetour = false;
|
||||
|
||||
// Je vais chercher les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare("SELECT * FROM thumbnails WHERE new_name = :newName");
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':newName', $newName, PDO::PARAM_STR);
|
||||
$req = MaBDD::getInstance()->prepare('SELECT * FROM thumbnails WHERE ' . $fromField . ' = :value');
|
||||
$req->bindValue(':value', $value);
|
||||
$req->execute();
|
||||
|
||||
// J'éclate les informations
|
||||
|
@ -72,17 +70,21 @@ class MiniatureObject extends RessourceObject implements RessourceInterface
|
|||
$this->setNbViewIPv6($resultat->nb_view_v6);
|
||||
$this->setMd5($resultat->md5);
|
||||
$this->setId($resultat->id);
|
||||
$this->setDateEnvoi($resultat->date_creation);
|
||||
$this->setNomNouveau($newName);
|
||||
$this->setIdImage($resultat->id_image);
|
||||
$this->setDateEnvoi($resultat->date_action);
|
||||
$this->setNomNouveau($resultat->new_name);
|
||||
$this->setIdImage($resultat->images_id);
|
||||
$this->setIsPreview($resultat->is_preview);
|
||||
|
||||
// Reprise des informations de l'image maitresse
|
||||
$imageMaitre = new ImageObject();
|
||||
$imageMaitre->charger($newName);
|
||||
$this->setBloquee($imageMaitre->isBloquee());
|
||||
$this->setSignalee($imageMaitre->isSignalee());
|
||||
$this->setNomOriginal($imageMaitre->getNomOriginal());
|
||||
$this->setIpEnvoi($imageMaitre->getIpEnvoi());
|
||||
$imageParente = new ImageObject();
|
||||
$imageParente->charger($this->getIdImage(), RessourceObject::SEARCH_BY_ID);
|
||||
$this->setBloquee($imageParente->isBloquee());
|
||||
$this->setSignalee($imageParente->isSignalee());
|
||||
$this->setApprouvee($imageParente->isApprouvee());
|
||||
$this->setNomOriginal($imageParente->getNomOriginal());
|
||||
$this->setIpEnvoi($imageParente->getIpEnvoi());
|
||||
$this->setIdProprietaire($imageParente->getIdProprietaire());
|
||||
$this->setSuspecte($imageParente->isSuspecte());
|
||||
|
||||
// Notification du chargement réussi
|
||||
$monRetour = true;
|
||||
|
@ -90,15 +92,13 @@ class MiniatureObject extends RessourceObject implements RessourceInterface
|
|||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sauver()
|
||||
public function sauver(): void
|
||||
{
|
||||
// J'enregistre les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare("UPDATE thumbnails SET id_image = :idImage, date_creation = :dateCreation, new_name = :newName, size = :size, height = :height, width = :width, last_view = :lastView, nb_view_v4 = :nbViewV4, nb_view_v6 = :nbViewV6, md5 = :md5 WHERE id = :id");
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE thumbnails SET images_id = :imagesId, is_preview = :isPreview, date_action = :dateCreation, new_name = :newName, size = :size, height = :height, width = :width, last_view = :lastView, nb_view_v4 = :nbViewV4, nb_view_v6 = :nbViewV6, md5 = :md5 WHERE id = :id');
|
||||
|
||||
$req->bindValue(':idImage', $this->getIdImage(), PDO::PARAM_INT);
|
||||
$req->bindValue(':imagesId', $this->getIdImage(), PDO::PARAM_INT);
|
||||
$req->bindValue(':isPreview', $this->getIsPreview(), PDO::PARAM_INT);
|
||||
$req->bindValue(':dateCreation', $this->getDateEnvoiBrute());
|
||||
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STMT);
|
||||
$req->bindValue(':size', $this->getPoids(), PDO::PARAM_INT);
|
||||
|
@ -107,44 +107,34 @@ class MiniatureObject extends RessourceObject implements RessourceInterface
|
|||
$req->bindValue(':lastView', $this->getLastView());
|
||||
$req->bindValue(':nbViewV4', $this->getNbViewIPv4(), PDO::PARAM_INT);
|
||||
$req->bindValue(':nbViewV6', $this->getNbViewIPv6(), PDO::PARAM_INT);
|
||||
$req->bindValue(':md5', $this->getMd5(), PDO::PARAM_STR);
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
|
||||
$req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supprimer()
|
||||
public function supprimer(): void
|
||||
{
|
||||
$monRetour = true;
|
||||
/**
|
||||
* Suppression de l'image en BDD
|
||||
*/
|
||||
$req = MaBDD::getInstance()->prepare("DELETE FROM thumbnails WHERE id = :id");
|
||||
/* @var $req PDOStatement */
|
||||
// Suppresion de l'image en BDD
|
||||
$req = MaBDD::getInstance()->prepare('DELETE FROM thumbnails WHERE id = :id');
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
$monRetour = $req->execute();
|
||||
|
||||
/**
|
||||
* Suppression du HDD
|
||||
*/
|
||||
if ($monRetour) {
|
||||
// Plus aucune miniature n'utilise le fichier (BDD déjà mise à jour !)
|
||||
if ($this->getNbDoublons() == 0) {
|
||||
// Je supprime l'image sur le HDD
|
||||
$monRetour = unlink($this->getPathMd5());
|
||||
}
|
||||
// Si plus aucune image n'utilise le fichier => supprimer l'image sur le HDD
|
||||
if (
|
||||
$req->execute()
|
||||
&& $this->getNbUsages() === 0
|
||||
&& file_exists($this->getPathMd5())
|
||||
) {
|
||||
unlink($this->getPathMd5());
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws Exception
|
||||
*/
|
||||
public function creer()
|
||||
public function creer(): bool
|
||||
{
|
||||
// Retour
|
||||
$monRetour = true;
|
||||
|
@ -171,7 +161,7 @@ class MiniatureObject extends RessourceObject implements RessourceInterface
|
|||
* Déplacement du fichier
|
||||
*/
|
||||
// Vérification de la non existence du fichier
|
||||
if ($this->getNbDoublons() == 0) {
|
||||
if ($this->getNbUsages() === 0) {
|
||||
$monRetour = rename($this->getPathTemp(), $this->getPathMd5());
|
||||
}
|
||||
|
||||
|
@ -190,14 +180,14 @@ class MiniatureObject extends RessourceObject implements RessourceInterface
|
|||
/**
|
||||
* Création en BDD
|
||||
*/
|
||||
$req = MaBDD::getInstance()->prepare("INSERT INTO thumbnails (id_image, date_creation, new_name, size, height, width, md5) VALUES (:idImage, NOW(), :newName, :size, :height, :width, :md5)");
|
||||
$req->bindValue(':idImage', $this->getIdImage(), PDO::PARAM_INT);
|
||||
$req = MaBDD::getInstance()->prepare('INSERT INTO thumbnails (images_id, date_action, new_name, size, height, width, md5) VALUES (:imagesId, NOW(), :newName, :size, :height, :width, :md5)');
|
||||
$req->bindValue(':imagesId', $this->getIdImage(), PDO::PARAM_INT);
|
||||
// Date : NOW()
|
||||
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STR);
|
||||
$req->bindValue(':newName', $this->getNomNouveau());
|
||||
$req->bindValue(':size', $this->getPoids(), PDO::PARAM_INT);
|
||||
$req->bindValue(':height', $this->getHauteur(), PDO::PARAM_INT);
|
||||
$req->bindValue(':width', $this->getLargeur(), PDO::PARAM_INT);
|
||||
$req->bindValue(':md5', $this->getMd5(), PDO::PARAM_STR);
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
|
||||
if (!$req->execute()) {
|
||||
// Gestion de l'erreur d'insertion en BDD
|
||||
|
@ -221,7 +211,7 @@ class MiniatureObject extends RessourceObject implements RessourceInterface
|
|||
* ID image parente
|
||||
* @return int
|
||||
*/
|
||||
public function getIdImage()
|
||||
public function getIdImage(): int
|
||||
{
|
||||
return $this->idImage;
|
||||
}
|
||||
|
@ -230,8 +220,24 @@ class MiniatureObject extends RessourceObject implements RessourceInterface
|
|||
* ID image parente
|
||||
* @param int $idImage
|
||||
*/
|
||||
public function setIdImage($idImage)
|
||||
public function setIdImage(int $idImage): void
|
||||
{
|
||||
$this->idImage = $idImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsPreview(): bool
|
||||
{
|
||||
return $this->isPreview;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isPreview
|
||||
*/
|
||||
public function setIsPreview(bool $isPreview): void
|
||||
{
|
||||
$this->isPreview = $isPreview;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
/**
|
||||
* Bibliothèque d'outils pour la gestion des images
|
||||
*/
|
||||
class Outils
|
||||
{
|
||||
|
||||
/**
|
||||
* Type de l'image
|
||||
* @param string $path chemin sur le filesystem
|
||||
* @return string
|
||||
*/
|
||||
public static function getType($path)
|
||||
{
|
||||
return exif_imagetype($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* MIME type de l'image
|
||||
* @param string $path chemin sur le filesystem
|
||||
* @return string
|
||||
*/
|
||||
public static function getMimeType($path)
|
||||
{
|
||||
return image_type_to_mime_type(self::getType($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Chargement ressource PHP image
|
||||
* @return resource
|
||||
*/
|
||||
public static function getImage($path)
|
||||
{
|
||||
$monImage = null;
|
||||
|
||||
// Je charge l'image en mémoire en fonction de son type
|
||||
switch (self::getType($path)) {
|
||||
case IMAGETYPE_GIF:
|
||||
$monImage = imagecreatefromgif($path);
|
||||
break;
|
||||
case IMAGETYPE_JPEG:
|
||||
$monImage = imagecreatefromjpeg($path);
|
||||
// Activation de l'entrelacement (image progressive)
|
||||
imageinterlace($monImage, true);
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
$monImage = imagecreatefrompng($path);
|
||||
// Gestion de la transparence
|
||||
imagealphablending($monImage, true);
|
||||
imagesavealpha($monImage, true);
|
||||
break;
|
||||
}
|
||||
|
||||
return $monImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enregistrement d'une ressource PHP image
|
||||
* @param ressource $uneImage Image a enregistrer
|
||||
* @param int $imageType type PHP de l'image
|
||||
* @param string $path chemin du fichier
|
||||
* @return boolean Succès ?
|
||||
*/
|
||||
public static function setImage($uneImage, $imageType, $path)
|
||||
{
|
||||
$monRetour = false;
|
||||
|
||||
// Je charge l'image en mémoire en fonction de son type
|
||||
switch ($imageType) {
|
||||
case IMAGETYPE_GIF:
|
||||
$monRetour = imagegif($uneImage, $path);
|
||||
break;
|
||||
case IMAGETYPE_JPEG:
|
||||
// Activation de l'entrelacement (image progressive)
|
||||
imageinterlace($uneImage, true);
|
||||
$monRetour = imagejpeg($uneImage, $path, 100);
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
// Gestion de la transparence
|
||||
imagealphablending($uneImage, true);
|
||||
imagesavealpha($uneImage, true);
|
||||
$monRetour = imagepng($uneImage, $path, 9);
|
||||
break;
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fourni l'extension officielle d'une ressource
|
||||
* @param string $path chemin sur le filesystem
|
||||
* @return string
|
||||
*/
|
||||
public static function getExtension($path)
|
||||
{
|
||||
$ext = image_type_to_extension(self::getType($path), false);
|
||||
if ($ext === 'jpeg') {
|
||||
// Préférence pour .jpg [filenmae.ext]
|
||||
$ext = 'jpg';
|
||||
}
|
||||
|
||||
return $ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Taille mémoire maximale autorisée
|
||||
* @see http://php.net/manual/fr/function.ini-get.php
|
||||
* @return int
|
||||
*/
|
||||
public static function getMemoireAllouee()
|
||||
{
|
||||
// Récupération de la valeur du php.ini
|
||||
$valBrute = trim(ini_get('memory_limit'));
|
||||
|
||||
// Gestion de l'unité multiplicatrice...
|
||||
$unite = strtolower(substr($valBrute, -1));
|
||||
$val = (int) substr($valBrute, 0, -1);
|
||||
switch ($unite) {
|
||||
case 'g':
|
||||
$val *= 1024;
|
||||
// no break
|
||||
case 'm':
|
||||
$val *= 1024;
|
||||
// no break
|
||||
case 'k':
|
||||
$val *= 1024;
|
||||
// no break
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Est-il possible de modifier l'image (mémoire suffisante ?)
|
||||
* @param string $path
|
||||
* @return boolean Possible ?
|
||||
* @see http://www.dotsamazing.com/en/labs/phpmemorylimit
|
||||
*/
|
||||
public static function isModifiableEnMemoire($path)
|
||||
{
|
||||
$monRetour = false;
|
||||
// Nombre de canaux d'information de l'image
|
||||
$nbCanaux = 4;
|
||||
|
||||
/**
|
||||
* Information sur les canaux ?
|
||||
*/
|
||||
$imageinfo = getimagesize($path);
|
||||
// Si information sur les canaux de l'image...
|
||||
if (isset($imageinfo['channels']) && is_int($imageinfo['channels'])) {
|
||||
$nbCanaux = $imageinfo['channels'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mémoire requise :
|
||||
* (hauteur x largeur x profondeur)
|
||||
* => x 2 [imageSource + imageDest]
|
||||
* => x 1.8 [fudge factor]
|
||||
*/
|
||||
$memReq = $imageinfo[1] * $imageinfo[0] * $nbCanaux;
|
||||
$memReq *= 2;
|
||||
$memReq *= _FUDGE_FACTOR_;
|
||||
|
||||
// Est-ce possible ?
|
||||
if ($memReq < self::getMemoireAllouee()) {
|
||||
$monRetour = true;
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dimension maximale acceptable en mémoire pour les images
|
||||
* <br />Suppose que l'image est carrée (donc indicatif !)
|
||||
* <br /> Suppose 4 canaux dans l'image
|
||||
* @return int
|
||||
* @see isModifiableEnMemoire
|
||||
*/
|
||||
public static function getMaxDimension()
|
||||
{
|
||||
$memDispo = self::getMemoireAllouee();
|
||||
|
||||
/**
|
||||
* Mémoire requise :
|
||||
* (hauteur x largeur x profondeur)
|
||||
* => x 2 [imageSource + imageDest]
|
||||
* => x 1.8 [fudge factor]
|
||||
*/
|
||||
$dimMax = round(sqrt($memDispo / 4 / 2 / _FUDGE_FACTOR_), 0);
|
||||
|
||||
return (int) $dimMax;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -26,29 +26,27 @@ namespace ImageHeberg;
|
|||
*/
|
||||
interface RessourceInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Crée sur le HDD et dans la BDD la ressource
|
||||
* @return boolean Résultat ?
|
||||
* @return bool Résultat ?
|
||||
*/
|
||||
public function creer();
|
||||
public function creer(): bool;
|
||||
|
||||
/**
|
||||
* Charge unn objet ressource depuis la BDD
|
||||
* @param string $nom Identifiant image-heberg
|
||||
* @return boolean Résultat ?
|
||||
* Charge un objet ressource depuis la BDD
|
||||
* @param string $value Identifiant image-heberg
|
||||
* @param string $fromField Champ à utiliser en BDD
|
||||
* @return bool Résultat ?
|
||||
*/
|
||||
public function charger($nom);
|
||||
public function charger(string $value, string $fromField = RessourceObject::SEARCH_BY_NAME): bool;
|
||||
|
||||
/**
|
||||
* Enregistre en BDD un objet ressource
|
||||
* @return boolean Résultat ?
|
||||
*/
|
||||
public function sauver();
|
||||
public function sauver(): void;
|
||||
|
||||
/**
|
||||
* Supprime sur le HDD et dans la BDD la ressource
|
||||
* @return boolean Résultat ?
|
||||
*/
|
||||
public function supprimer();
|
||||
public function supprimer(): void;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,6 +21,8 @@
|
|||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use Exception;
|
||||
use ImagickException;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
|
@ -28,52 +30,67 @@ use PDO;
|
|||
*/
|
||||
abstract class RessourceObject
|
||||
{
|
||||
public const TYPE_IMAGE = 1;
|
||||
public const TYPE_MINIATURE = 2;
|
||||
// Types de ressources
|
||||
final public const int TYPE_IMAGE = 1;
|
||||
final public const int TYPE_MINIATURE = 2;
|
||||
|
||||
private $id;
|
||||
private $nomOriginal;
|
||||
private $nomNouveau;
|
||||
private $largeur;
|
||||
private $hauteur;
|
||||
private $poids;
|
||||
private $lastView;
|
||||
private $nbViewIPv4;
|
||||
private $nbViewIPv6;
|
||||
private $dateEnvoi;
|
||||
private $md5;
|
||||
private $ipEnvoi;
|
||||
private $isBloquee;
|
||||
private $isSignalee;
|
||||
private $pathTemp;
|
||||
private $type;
|
||||
private $nomTemp;
|
||||
// Champ à utiliser en BDD pour charger la ressource
|
||||
final public const string SEARCH_BY_MD5 = 'md5';
|
||||
final public const string SEARCH_BY_NAME = 'new_name';
|
||||
final public const string SEARCH_BY_ID = 'id';
|
||||
|
||||
// Attributs de la classe
|
||||
private int $id = 0;
|
||||
private string $nomOriginal = '';
|
||||
private string $nomNouveau = '';
|
||||
private int $largeur = 0;
|
||||
private int $hauteur = 0;
|
||||
private int $poids = 0;
|
||||
private string $lastView = '0000-00-00';
|
||||
private int $nbViewIPv4 = 0;
|
||||
private int $nbViewIPv6 = 0;
|
||||
private string $dateEnvoi = '';
|
||||
private ?string $md5 = null;
|
||||
private string $ipEnvoi = '';
|
||||
private bool $isBloquee = false;
|
||||
private bool $isSignalee = false;
|
||||
private bool $isApprouvee = false;
|
||||
private bool $isSuspecte = false;
|
||||
private string $pathTemp = '';
|
||||
private int $type = self::TYPE_IMAGE;
|
||||
private string $nomTemp = '';
|
||||
private ?int $idProprietaire = null;
|
||||
|
||||
/**
|
||||
* Génère le nom d'une nouvelle image
|
||||
* @param int $nb nombre de chiffres à rajouter à la fin du nom
|
||||
* @return string nom de l'image
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function genererNom($nb = 0)
|
||||
protected function genererNom(int $nb = 0): string
|
||||
{
|
||||
// Random pour unicité + cassage lien nom <-> @IP
|
||||
$random = rand(100, 999);
|
||||
$random = random_int(100, 999);
|
||||
// @IP expéditeur
|
||||
$adresseIP = abs(crc32($_SERVER['REMOTE_ADDR'] . $random));
|
||||
// Timestamp d'envoi
|
||||
$timestamp = $_SERVER['REQUEST_TIME'];
|
||||
|
||||
// Calcul du nom de l'image
|
||||
$new_name = $timestamp . $adresseIP . substr($random, 0, $nb) . '.' . Outils::getExtension($this->getPathTemp());
|
||||
// Taille max : 28 chr
|
||||
// - Timestamp : 1699048241 : 10 caractères jusqu'en 2286...
|
||||
// - $adresseIP -> CRC32 : 8 bits en hexa, soit 16^8 valeurs => 4 294 967 296 : 10 caractères
|
||||
// - Suffixe anti-doublon : hypothèse très haute 10k doublons : 4 caractères
|
||||
// - Extension : 1+3 caractères
|
||||
|
||||
return $new_name;
|
||||
// Calcul du nom de l'image
|
||||
return $timestamp . $adresseIP . substr($random, 0, $nb) . '.' . HelperImage::getExtension($this->getPathTemp());
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5 de la ressource
|
||||
* @return string
|
||||
*/
|
||||
public function getMd5()
|
||||
public function getMd5(): string
|
||||
{
|
||||
// Création d'une image => Utilisation du fichier temporaire
|
||||
if (is_null($this->md5) && $this->getPathTemp()) {
|
||||
|
@ -88,13 +105,9 @@ abstract class RessourceObject
|
|||
* Path sur le HDD
|
||||
* @return string
|
||||
*/
|
||||
public function getPathMd5()
|
||||
public function getPathMd5(): string
|
||||
{
|
||||
// Path final
|
||||
$pathFinal = '';
|
||||
|
||||
// Path du type d'image
|
||||
$pathDuType = '';
|
||||
if ($this->getType() === self::TYPE_IMAGE) {
|
||||
// Image
|
||||
$pathDuType = _PATH_IMAGES_;
|
||||
|
@ -103,8 +116,9 @@ abstract class RessourceObject
|
|||
$pathDuType = _PATH_MINIATURES_;
|
||||
}
|
||||
|
||||
// Path final
|
||||
if ($this->getType() === self::TYPE_IMAGE && ($this->getId() === 1 || $this->getId() === 2)) {
|
||||
// Gestion des images spécificques 404 / ban
|
||||
// Gestion des images spécifiques 404 / ban
|
||||
$pathFinal = $pathDuType . $this->getNomNouveau();
|
||||
} else {
|
||||
// Cas par défaut
|
||||
|
@ -117,39 +131,40 @@ abstract class RessourceObject
|
|||
|
||||
/**
|
||||
* Nombre d'images ayant le même MD5 (Normalement 1 à minima, l'image courante...)
|
||||
* @return int nombre d'images ayant ce MD5 (-1 en cas d'erreur)
|
||||
* @return int nombre d'images ayant ce MD5 (0 par défaut)
|
||||
*/
|
||||
public function getNbDoublons()
|
||||
public function getNbUsages(): int
|
||||
{
|
||||
// Retour - -1 par défaut pour marquer l'erreur
|
||||
$monRetour = -1;
|
||||
$monRetour = 0;
|
||||
|
||||
// Existe-t-il d'autres occurences de cette image ?
|
||||
if ($this->getType() === self::TYPE_IMAGE) {
|
||||
// Image
|
||||
$req = MaBDD::getInstance()->prepare("SELECT COUNT(*) AS nb FROM images WHERE md5 = :md5");
|
||||
} else {
|
||||
// Miniature
|
||||
$req = MaBDD::getInstance()->prepare("SELECT COUNT(*) AS nb FROM thumbnails WHERE md5 = :md5");
|
||||
}
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':md5', $this->getMd5(), PDO::PARAM_STR);
|
||||
$req->execute();
|
||||
$values = $req->fetch();
|
||||
if ($values !== false) {
|
||||
$monRetour = (int) $values->nb;
|
||||
// Si l'image n'existe pas et qu'on est pas en train de l'envoyer, ne pas tenter de la charger
|
||||
if (!is_null($this->md5) || $this->getPathTemp()) {
|
||||
// Existe-t-il d'autres occurences de cette image ?
|
||||
if ($this->getType() === self::TYPE_IMAGE) {
|
||||
// Image
|
||||
$req = MaBDD::getInstance()->prepare('SELECT COUNT(*) AS nb FROM images WHERE md5 = :md5');
|
||||
} else {
|
||||
// Miniature
|
||||
$req = MaBDD::getInstance()->prepare('SELECT COUNT(*) AS nb FROM thumbnails WHERE md5 = :md5');
|
||||
}
|
||||
$req->bindValue(':md5', $this->getMd5());
|
||||
$req->execute();
|
||||
$resultat = $req->fetch();
|
||||
if ($resultat !== false) {
|
||||
$monRetour = (int)$resultat->nb;
|
||||
}
|
||||
}
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL de la ressource
|
||||
* @param bool $forceHttps Forcer le HTTPS ?
|
||||
* @return string
|
||||
*/
|
||||
public function getURL()
|
||||
public function getURL(bool $forceHttps = false): string
|
||||
{
|
||||
// Path du type d'image
|
||||
$urlDuType = '';
|
||||
if ($this->getType() === self::TYPE_IMAGE) {
|
||||
// Image
|
||||
$urlDuType = _URL_IMAGES_;
|
||||
|
@ -158,54 +173,41 @@ abstract class RessourceObject
|
|||
$urlDuType = _URL_MINIATURES_;
|
||||
}
|
||||
|
||||
// Forcer le HTTPS ?
|
||||
if ($forceHttps) {
|
||||
$urlDuType = str_replace('http:/', 'https:/', $urlDuType);
|
||||
}
|
||||
|
||||
return $urlDuType . $this->getNomNouveau();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotation d'une ressource <br />
|
||||
* Inclus mise à jour largeur / hauteur / poids de l'image
|
||||
* @param int $angle xxx° de rotation GAUCHE
|
||||
* @param int $angle xxx° de rotation horaire
|
||||
* @param string $pathSrc chemin de la ressource d'origine
|
||||
* @param string $pathDst chemin de la ressource de destination
|
||||
* @return boolean succès ?
|
||||
* @return bool succès ?
|
||||
* @throws ImagickException
|
||||
*/
|
||||
public function rotation($angle, $pathSrc, $pathDst)
|
||||
public function rotation(int $angle, string $pathSrc, string $pathDst): bool
|
||||
{
|
||||
// Je charge l'image en mémoire
|
||||
$resImg = Outils::getImage($pathSrc);
|
||||
// Je vérifie que tout va bien
|
||||
if ($resImg === false) {
|
||||
return false;
|
||||
$resImg = HelperImage::getImage($pathSrc);
|
||||
|
||||
// Rotation (Imagick est dans le sens horaire, imagerotate dans le sens anti-horaire)
|
||||
if (HelperImage::getType($pathSrc) === IMAGETYPE_GIF) {
|
||||
// Image animée (GIF) : c'est une succession d'images !
|
||||
foreach ($resImg as $frame) {
|
||||
$frame->rotateImage('rgb(0,0,0)', $angle);
|
||||
}
|
||||
} else {
|
||||
// Cas standard (image non animée)
|
||||
$resImg->rotateImage('rgb(0,0,0)', $angle);
|
||||
}
|
||||
|
||||
// J'effectue la rotation
|
||||
$imgRotate = imagerotate($resImg, $angle, 0);
|
||||
|
||||
// Je vérifie que tout va bien
|
||||
if ($imgRotate === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Nettoyage mémoire (image d'origine)
|
||||
imagedestroy($resImg);
|
||||
|
||||
// J'enregistre l'image
|
||||
$retour = Outils::setImage($imgRotate, Outils::getType($pathSrc), $pathDst);
|
||||
|
||||
// La création du fichier s'est bien passé ?
|
||||
if ($retour === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mise à jour des propriétés de l'image
|
||||
// Dimensions
|
||||
$this->setLargeur(imagesx($imgRotate));
|
||||
$this->setHauteur(imagesy($imgRotate));
|
||||
|
||||
// Poids de l'image
|
||||
$this->setPoids(filesize($pathDst));
|
||||
|
||||
return $retour;
|
||||
return HelperImage::setImage($resImg, HelperImage::getType($pathSrc), $pathDst);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,81 +216,53 @@ abstract class RessourceObject
|
|||
* @param string $pathDst chemin de la ressource de destination
|
||||
* @param int $largeurDemandee largeur souhaitée
|
||||
* @param int $hauteurDemandee hauteur souhaitée
|
||||
* @return boolean réussi ?
|
||||
* @return bool réussi ?
|
||||
* @throws ImagickException
|
||||
*/
|
||||
public function redimensionner($pathSrc, $pathDst, $largeurDemandee, $hauteurDemandee)
|
||||
public function redimensionner(string $pathSrc, string $pathDst, int $largeurDemandee, int $hauteurDemandee): bool
|
||||
{
|
||||
// Chargement de l'image
|
||||
$monImage = Outils::getImage($pathSrc);
|
||||
$monImage = HelperImage::getImage($pathSrc);
|
||||
|
||||
// Récupération de ses dimensions
|
||||
$largeurImage = imagesx($monImage);
|
||||
$hauteurImage = imagesy($monImage);
|
||||
$largeurImage = $monImage->getImageWidth();
|
||||
$hauteurImage = $monImage->getImageHeight();
|
||||
|
||||
// Dimension nulle : on arrête
|
||||
// Dimensions incohérentes : on arrête
|
||||
if ($hauteurImage <= 0 || $hauteurDemandee <= 0 || $largeurImage <= 0 || $largeurDemandee <= 0 || $largeurImage <= $largeurDemandee || $hauteurImage <= $hauteurDemandee) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Nicolas
|
||||
*/
|
||||
if ($largeurImage > $hauteurImage) {
|
||||
// Format paysage
|
||||
$largeurMax = max(array($largeurDemandee, $hauteurDemandee));
|
||||
$hauteurMax = min(array($largeurDemandee, $hauteurDemandee));
|
||||
// Redimensionnement par Imagick
|
||||
if (HelperImage::getType($pathSrc) === IMAGETYPE_GIF) {
|
||||
// Cas image animée (GIF) : c'est une succession d'images !
|
||||
foreach ($monImage as $frame) {
|
||||
$frame->thumbnailImage($largeurDemandee, $hauteurDemandee, true);
|
||||
}
|
||||
} else {
|
||||
// Format portrait ou carré
|
||||
$largeurMax = min(array($largeurDemandee, $hauteurDemandee));
|
||||
$hauteurMax = max(array($largeurDemandee, $hauteurDemandee));
|
||||
// Cas standard (image non animée)
|
||||
$monImage->thumbnailImage($largeurDemandee, $hauteurDemandee, true);
|
||||
}
|
||||
// Calcul du ratio
|
||||
$monRatio = min(array($largeurMax / $largeurImage, $hauteurMax / $hauteurImage));
|
||||
|
||||
// Dimensions finales
|
||||
$largeurFinale = round($largeurImage * $monRatio);
|
||||
$hauteurFinale = round($hauteurImage * $monRatio);
|
||||
|
||||
// Debug
|
||||
if (_PHPUNIT_) {
|
||||
echo "Initial : " . $largeurImage . " x " . $hauteurImage . "\r\n";
|
||||
echo "Demandé : " . $largeurDemandee . " x " . $hauteurDemandee . "\r\n";
|
||||
echo "Fourni : " . $largeurFinale . " x " . $hauteurFinale . "\r\n";
|
||||
}
|
||||
|
||||
// Redimensionnement (en mémoire)
|
||||
$newImage = imagescale($monImage, $largeurFinale, $hauteurFinale);
|
||||
|
||||
// Ecriture de l'image
|
||||
$monRetour = Outils::setImage($newImage, Outils::getType($pathSrc), $pathDst);
|
||||
|
||||
return $monRetour;
|
||||
return HelperImage::setImage($monImage, HelperImage::getType($pathSrc), $pathDst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cet utilisateur est-il propriétaire de l'image ?
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isProprietaire()
|
||||
public function isProprietaire(): bool
|
||||
{
|
||||
$monRetour = false;
|
||||
|
||||
// Je vais chercher les infos en BDD
|
||||
$req = MaBDD::getInstance()->prepare("SELECT * FROM possede WHERE image_id = :imageId");
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':imageId', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
|
||||
// Je récupère les potentielles valeurs
|
||||
$values = $req->fetch();
|
||||
|
||||
// Si l'image à un propriétaire...
|
||||
if ($values !== false) {
|
||||
if ($this->getIdProprietaire() !== null) {
|
||||
// Le propriétaire est-il connecté ?
|
||||
$uneSession = new SessionObject();
|
||||
|
||||
// Est-ce le propriétaire de l'image ?
|
||||
if ((int) $values->pk_membres === $uneSession->getId()) {
|
||||
if ($this->getIdProprietaire() === $uneSession->getId()) {
|
||||
// Si oui... on confirme !
|
||||
$monRetour = true;
|
||||
}
|
||||
|
@ -301,62 +275,96 @@ abstract class RessourceObject
|
|||
* Date d'envoi formatée
|
||||
* @return string
|
||||
*/
|
||||
public function getDateEnvoiFormatee()
|
||||
public function getDateEnvoiFormatee(): string
|
||||
{
|
||||
$phpdate = strtotime($this->getDateEnvoiBrute());
|
||||
return date("d/m/Y H:i:s", $phpdate);
|
||||
return date('d/m/Y H:i:s', $phpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date de dernier affichage formaté
|
||||
* @return string
|
||||
*/
|
||||
public function getLastViewFormate()
|
||||
public function getLastViewFormate(): string
|
||||
{
|
||||
$phpdate = strtotime($this->getLastView());
|
||||
$monRetour = '?';
|
||||
if ($this->getLastView() !== '0000-00-00') {
|
||||
$phpdate = strtotime($this->getLastView());
|
||||
|
||||
// Gestion du cas de non affichage
|
||||
if ($phpdate === 0) {
|
||||
return "-";
|
||||
// Gestion du cas de non affichage
|
||||
if ($phpdate !== 0 && $phpdate !== false) {
|
||||
$monRetour = date('d/m/Y', $phpdate);
|
||||
}
|
||||
}
|
||||
return date("d/m/Y", $phpdate);
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nombre d'appels IPv4 & IPv6
|
||||
* @return int
|
||||
*/
|
||||
public function getNbViewTotal()
|
||||
public function getNbViewTotal(): int
|
||||
{
|
||||
return (int) $this->getNbViewIPv4() + $this->getNbViewIPv6();
|
||||
return $this->getNbViewIPv4() + $this->getNbViewIPv6();
|
||||
}
|
||||
|
||||
/**
|
||||
* Nombre d'affichage par jour
|
||||
* @return int
|
||||
*/
|
||||
public function getNbViewPerDay(): int
|
||||
{
|
||||
// date_diff ne comptabilise que les journées entières, alors qu'en SQL, on compare des dates
|
||||
// date_diff('2023-09-03 23:38:42', '2023-09-05 22:53:03') => 1
|
||||
// date_diff('2023-09-03', '2023-09-05 22:53:03') => 2
|
||||
// => substr() de la date d'envoi pour aligner sur les valeurs du SQL
|
||||
$nbJours = (int)date_diff(date_create(substr($this->getDateEnvoiBrute(), 0, 10)), date_create())->format('%r%a');
|
||||
|
||||
// Le premier jour, autoriser les xxx vues de la journée
|
||||
if ($nbJours === 0) {
|
||||
$nbJours = 1;
|
||||
}
|
||||
|
||||
return (int)($this->getNbViewTotal() / $nbJours);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nom original de la ressource
|
||||
* @return string
|
||||
*/
|
||||
public function getNomOriginalFormate()
|
||||
public function getNomOriginalFormate(): string
|
||||
{
|
||||
return htmlentities($this->nomOriginal);
|
||||
return htmlentities($this->nomOriginal, ENT_SUBSTITUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Incrémente le nombre d'affichage IPv4
|
||||
* Met à jour les statistiques (nb d'affichage et date) en BDD
|
||||
*/
|
||||
public function setNbViewIpv4PlusUn()
|
||||
public function updateStatsAffichage(string $remoteAddr): void
|
||||
{
|
||||
$this->nbViewIPv4 = $this->getNbViewIPv4() + 1;
|
||||
$this->setLastView(date("Y-m-d"));
|
||||
// Prendre la bonne table
|
||||
if ($this->getType() === self::TYPE_IMAGE) {
|
||||
// Image
|
||||
$table = 'images';
|
||||
} else {
|
||||
// Miniature
|
||||
$table = 'thumbnails';
|
||||
}
|
||||
|
||||
// Prendre le bon type d'@ IP
|
||||
if (filter_var($remoteAddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
// IPv4
|
||||
$typeAcces = 'nb_view_v4';
|
||||
} else {
|
||||
// IPv6
|
||||
$typeAcces = 'nb_view_v6';
|
||||
}
|
||||
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE ' . $table . ' SET last_view = NOW(), ' . $typeAcces . ' = ' . $typeAcces . ' + 1 WHERE id = :id');
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Incrémente le nombre d'affichage IPv6
|
||||
*/
|
||||
public function setNbViewIpv6PlusUn()
|
||||
{
|
||||
$this->nbViewIPv6 = $this->getNbViewIPv6() + 1;
|
||||
$this->setLastView(date("Y-m-d"));
|
||||
}
|
||||
/**
|
||||
* GETTERS ET SETTERS
|
||||
*/
|
||||
|
@ -365,16 +373,16 @@ abstract class RessourceObject
|
|||
* ID de la ressource
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
public function getId(): int
|
||||
{
|
||||
return (int) $this->id;
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nom original de la ressource
|
||||
* @return string
|
||||
*/
|
||||
protected function getNomOriginal()
|
||||
protected function getNomOriginal(): string
|
||||
{
|
||||
return $this->nomOriginal;
|
||||
}
|
||||
|
@ -383,7 +391,7 @@ abstract class RessourceObject
|
|||
* Nom image-heberg
|
||||
* @return string
|
||||
*/
|
||||
public function getNomNouveau()
|
||||
public function getNomNouveau(): string
|
||||
{
|
||||
return $this->nomNouveau;
|
||||
}
|
||||
|
@ -392,42 +400,43 @@ abstract class RessourceObject
|
|||
* Largeur en px
|
||||
* @return int
|
||||
*/
|
||||
public function getLargeur()
|
||||
public function getLargeur(): int
|
||||
{
|
||||
return (int) $this->largeur;
|
||||
return $this->largeur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauteur en px
|
||||
* @return int
|
||||
*/
|
||||
public function getHauteur()
|
||||
public function getHauteur(): int
|
||||
{
|
||||
return (int) $this->hauteur;
|
||||
return $this->hauteur;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poids de la ressource
|
||||
* @return int
|
||||
*/
|
||||
public function getPoids()
|
||||
public function getPoids(): int
|
||||
{
|
||||
return (int) $this->poids;
|
||||
return $this->poids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poids de la ressource en Mo
|
||||
* @return float
|
||||
*/
|
||||
public function getPoidsMo() {
|
||||
return round($this->getPoids() /1024/1024, 1);
|
||||
public function getPoidsMo(): float
|
||||
{
|
||||
return round($this->getPoids() / 1024 / 1024, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Date de dernier affichage
|
||||
* @return type
|
||||
* @return string
|
||||
*/
|
||||
protected function getLastView()
|
||||
protected function getLastView(): string
|
||||
{
|
||||
return $this->lastView;
|
||||
}
|
||||
|
@ -436,25 +445,25 @@ abstract class RessourceObject
|
|||
* Nb d'affichage en IPv4
|
||||
* @return int
|
||||
*/
|
||||
protected function getNbViewIPv4()
|
||||
protected function getNbViewIPv4(): int
|
||||
{
|
||||
return (int) $this->nbViewIPv4;
|
||||
return $this->nbViewIPv4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nb d'affichage en IPv6
|
||||
* @return int
|
||||
*/
|
||||
protected function getNbViewIPv6()
|
||||
protected function getNbViewIPv6(): int
|
||||
{
|
||||
return (int) $this->nbViewIPv6;
|
||||
return $this->nbViewIPv6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date d'envoi du fichier
|
||||
* @return type
|
||||
* @return string
|
||||
*/
|
||||
public function getDateEnvoiBrute()
|
||||
public function getDateEnvoiBrute(): string
|
||||
{
|
||||
return $this->dateEnvoi;
|
||||
}
|
||||
|
@ -463,43 +472,61 @@ abstract class RessourceObject
|
|||
* @ IP d'envoi
|
||||
* @return string
|
||||
*/
|
||||
public function getIpEnvoi()
|
||||
public function getIpEnvoi(): string
|
||||
{
|
||||
return $this->ipEnvoi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image bloquée ?
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isBloquee()
|
||||
public function isBloquee(): bool
|
||||
{
|
||||
return $this->isBloquee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image signalée ?
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isSignalee()
|
||||
public function isSignalee(): bool
|
||||
{
|
||||
return $this->isSignalee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image approuvée (marquée comme valide)
|
||||
* @return bool
|
||||
*/
|
||||
public function isApprouvee(): bool
|
||||
{
|
||||
return $this->isApprouvee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image envoyée depuis un réseau suspect
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuspecte(): bool
|
||||
{
|
||||
return $this->isSuspecte;
|
||||
}
|
||||
|
||||
/**
|
||||
* Path temporaire (upload d'image)
|
||||
* @return string
|
||||
*/
|
||||
public function getPathTemp()
|
||||
public function getPathTemp(): string
|
||||
{
|
||||
return $this->pathTemp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type d'image
|
||||
* @return int ressoruceObject const
|
||||
* @return int ressourceObject const
|
||||
*/
|
||||
public function getType()
|
||||
public function getType(): int
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
@ -508,7 +535,7 @@ abstract class RessourceObject
|
|||
* Nom temporaire (PC utilisateur - upload d'image)
|
||||
* @return string
|
||||
*/
|
||||
public function getNomTemp()
|
||||
public function getNomTemp(): string
|
||||
{
|
||||
return $this->nomTemp;
|
||||
}
|
||||
|
@ -517,7 +544,7 @@ abstract class RessourceObject
|
|||
* Nom temporaire (PC utilisateur - upload d'image)
|
||||
* @param string $nomTemp
|
||||
*/
|
||||
public function setNomTemp($nomTemp)
|
||||
public function setNomTemp(string $nomTemp): void
|
||||
{
|
||||
$this->nomTemp = $nomTemp;
|
||||
}
|
||||
|
@ -526,7 +553,7 @@ abstract class RessourceObject
|
|||
* Type d'image
|
||||
* @param int $type RessourceObject const
|
||||
*/
|
||||
public function setType($type)
|
||||
public function setType(int $type): void
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
@ -535,34 +562,52 @@ abstract class RessourceObject
|
|||
* Path temporaire (upload d'image)
|
||||
* @param string $pathTemp
|
||||
*/
|
||||
public function setPathTemp($pathTemp)
|
||||
public function setPathTemp(string $pathTemp): void
|
||||
{
|
||||
$this->pathTemp = $pathTemp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image bloquée ?
|
||||
* @param boolean $bloquee
|
||||
* @param bool $bloquee
|
||||
*/
|
||||
public function setBloquee($bloquee)
|
||||
public function setBloquee(bool $bloquee): void
|
||||
{
|
||||
$this->isBloquee = $bloquee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image signalée ?
|
||||
* @param boolean $isSignalee
|
||||
* @param bool $isSignalee
|
||||
*/
|
||||
public function setSignalee($isSignalee)
|
||||
public function setSignalee(bool $isSignalee): void
|
||||
{
|
||||
$this->isSignalee = $isSignalee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image approuvée (marquée comme valide) ?
|
||||
* @param bool $isApprouvee
|
||||
*/
|
||||
public function setApprouvee(bool $isApprouvee): void
|
||||
{
|
||||
$this->isApprouvee = $isApprouvee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image envoyée depuis un réseau suspect
|
||||
* @param bool $isSuspecte
|
||||
*/
|
||||
public function setSuspecte(bool $isSuspecte): void
|
||||
{
|
||||
$this->isSuspecte = $isSuspecte;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID de l'image
|
||||
* @param int $id
|
||||
*/
|
||||
protected function setId($id)
|
||||
protected function setId(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
@ -571,7 +616,7 @@ abstract class RessourceObject
|
|||
* Nom original de la ressource
|
||||
* @param string $nomOriginal
|
||||
*/
|
||||
protected function setNomOriginal($nomOriginal)
|
||||
protected function setNomOriginal(string $nomOriginal): void
|
||||
{
|
||||
$this->nomOriginal = $nomOriginal;
|
||||
}
|
||||
|
@ -580,7 +625,7 @@ abstract class RessourceObject
|
|||
* Nom image-heberg
|
||||
* @param string $nomNouveau
|
||||
*/
|
||||
protected function setNomNouveau($nomNouveau)
|
||||
protected function setNomNouveau(string $nomNouveau): void
|
||||
{
|
||||
$this->nomNouveau = $nomNouveau;
|
||||
}
|
||||
|
@ -589,7 +634,7 @@ abstract class RessourceObject
|
|||
* Largeur en px
|
||||
* @param int $largeur
|
||||
*/
|
||||
protected function setLargeur($largeur)
|
||||
protected function setLargeur(int $largeur): void
|
||||
{
|
||||
$this->largeur = $largeur;
|
||||
}
|
||||
|
@ -598,7 +643,7 @@ abstract class RessourceObject
|
|||
* Hauteur en px
|
||||
* @param int $hauteur
|
||||
*/
|
||||
protected function setHauteur($hauteur)
|
||||
protected function setHauteur(int $hauteur): void
|
||||
{
|
||||
$this->hauteur = $hauteur;
|
||||
}
|
||||
|
@ -607,17 +652,21 @@ abstract class RessourceObject
|
|||
* Poids de la ressource
|
||||
* @param int $poids
|
||||
*/
|
||||
protected function setPoids($poids)
|
||||
protected function setPoids(int $poids): void
|
||||
{
|
||||
$this->poids = $poids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date de dernier affichage
|
||||
* @param type $lastView
|
||||
* @param ?string $lastView
|
||||
*/
|
||||
protected function setLastView($lastView)
|
||||
protected function setLastView(?string $lastView): void
|
||||
{
|
||||
if (is_null($lastView)) {
|
||||
// Si l'image n'a jamais été affichée, elle est à NULL en BDD
|
||||
$lastView = '';
|
||||
}
|
||||
$this->lastView = $lastView;
|
||||
}
|
||||
|
||||
|
@ -625,7 +674,7 @@ abstract class RessourceObject
|
|||
* Nb d'affichage en IPv4
|
||||
* @param int $nbViewIPv4
|
||||
*/
|
||||
protected function setNbViewIPv4($nbViewIPv4)
|
||||
protected function setNbViewIPv4(int $nbViewIPv4): void
|
||||
{
|
||||
$this->nbViewIPv4 = $nbViewIPv4;
|
||||
}
|
||||
|
@ -634,16 +683,16 @@ abstract class RessourceObject
|
|||
* Nb d'affichage en IPv6
|
||||
* @param int $nbViewIPv6
|
||||
*/
|
||||
protected function setNbViewIPv6($nbViewIPv6)
|
||||
protected function setNbViewIPv6(int $nbViewIPv6): void
|
||||
{
|
||||
$this->nbViewIPv6 = $nbViewIPv6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date d'envoi du fichier
|
||||
* @param type $dateEnvoi
|
||||
* @param string $dateEnvoi
|
||||
*/
|
||||
protected function setDateEnvoi($dateEnvoi)
|
||||
protected function setDateEnvoi(string $dateEnvoi): void
|
||||
{
|
||||
$this->dateEnvoi = $dateEnvoi;
|
||||
}
|
||||
|
@ -652,7 +701,7 @@ abstract class RessourceObject
|
|||
* MD5 de la ressource
|
||||
* @param string $md5
|
||||
*/
|
||||
protected function setMd5($md5)
|
||||
protected function setMd5(string $md5): void
|
||||
{
|
||||
$this->md5 = $md5;
|
||||
}
|
||||
|
@ -661,8 +710,26 @@ abstract class RessourceObject
|
|||
* @ IP d'envoi
|
||||
* @param string $ipEnvoi
|
||||
*/
|
||||
protected function setIpEnvoi($ipEnvoi)
|
||||
protected function setIpEnvoi(string $ipEnvoi): void
|
||||
{
|
||||
$this->ipEnvoi = $ipEnvoi;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID du compte propriétaire de l'image
|
||||
* @return ?int
|
||||
*/
|
||||
public function getIdProprietaire(): ?int
|
||||
{
|
||||
return $this->idProprietaire;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ?int $idProprietaire ID du compte propriétaire de l'image
|
||||
* @return void
|
||||
*/
|
||||
protected function setIdProprietaire(?int $idProprietaire): void
|
||||
{
|
||||
$this->idProprietaire = $idProprietaire;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -27,26 +27,23 @@ namespace ImageHeberg;
|
|||
class SessionObject
|
||||
{
|
||||
// @ IP de l'utilisateur
|
||||
private $IP;
|
||||
private string $IP = '';
|
||||
// Objet utilisateur
|
||||
private $userObject;
|
||||
private UtilisateurObject $userObject;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// Je vérifie qu'une session n'est pas déjà lancée & que pas tests travis (session_start déjà effectué)
|
||||
if (session_status() === PHP_SESSION_NONE && !_PHPUNIT_) {
|
||||
if (!_PHPUNIT_ && session_status() === PHP_SESSION_NONE) {
|
||||
// Je lance la session côté PHP
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Si j'ai déjà une session existante
|
||||
if (isset($_SESSION['userObject'])) {
|
||||
// Si l'@ IP correspond
|
||||
if ($_SESSION['IP'] === $_SERVER['REMOTE_ADDR']) {
|
||||
// On recharge les informations
|
||||
$this->setIP($_SESSION['IP']);
|
||||
$this->setUserObject($_SESSION['userObject']);
|
||||
}
|
||||
// Si j'ai déjà une session existante && que l'@ IP correspond
|
||||
if (isset($_SESSION['userObject']) && $_SESSION['IP'] === $_SERVER['REMOTE_ADDR']) {
|
||||
// On recharge les informations
|
||||
$this->setIP($_SESSION['IP']);
|
||||
$this->setUserObject($_SESSION['userObject']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,20 +51,16 @@ class SessionObject
|
|||
* Mon utilisateur
|
||||
* @return UtilisateurObject
|
||||
*/
|
||||
private function getUserObject()
|
||||
private function getUserObject(): UtilisateurObject
|
||||
{
|
||||
if (isset($this->userObject)) {
|
||||
return $this->userObject;
|
||||
} else {
|
||||
return new UtilisateurObject();
|
||||
}
|
||||
return $this->userObject ?? new UtilisateurObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mon utilisateur
|
||||
* @param UtilisateurObject $userObject Objet utilisateur
|
||||
*/
|
||||
public function setUserObject($userObject)
|
||||
public function setUserObject(UtilisateurObject $userObject): void
|
||||
{
|
||||
$this->userObject = $userObject;
|
||||
$_SESSION['userObject'] = $userObject;
|
||||
|
@ -77,7 +70,7 @@ class SessionObject
|
|||
* Nom d'utilisateur
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName()
|
||||
public function getUserName(): string
|
||||
{
|
||||
return $this->getUserObject()->getUserName();
|
||||
}
|
||||
|
@ -86,16 +79,16 @@ class SessionObject
|
|||
* @ IP
|
||||
* @return string
|
||||
*/
|
||||
public function getIP()
|
||||
public function getIP(): string
|
||||
{
|
||||
return $this->IP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Niveau de droits
|
||||
* @return type
|
||||
* @return int
|
||||
*/
|
||||
public function getLevel()
|
||||
public function getLevel(): int
|
||||
{
|
||||
return $this->getUserObject()->getLevel();
|
||||
}
|
||||
|
@ -104,16 +97,16 @@ class SessionObject
|
|||
* ID en BDD
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
public function getId(): int
|
||||
{
|
||||
return (int) $this->getUserObject()->getId();
|
||||
return $this->getUserObject()->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* IP
|
||||
* @param string $IP
|
||||
*/
|
||||
public function setIP($IP)
|
||||
public function setIP(string $IP): void
|
||||
{
|
||||
$this->IP = $IP;
|
||||
// On enregistre dans la session
|
||||
|
@ -122,22 +115,22 @@ class SessionObject
|
|||
|
||||
/**
|
||||
* Vérification des droits de l'utilisateur pour la page
|
||||
* @param type $levelRequis
|
||||
* @return boolean
|
||||
* @param int $levelRequis
|
||||
* @return bool
|
||||
*/
|
||||
public function verifierDroits($levelRequis)
|
||||
public function verifierDroits(int $levelRequis): bool
|
||||
{
|
||||
$monRetour = false;
|
||||
if ($this->getLevel() >= $levelRequis) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
$monRetour = true;
|
||||
}
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Déconnexion d'un utilisateur
|
||||
*/
|
||||
public function deconnexion()
|
||||
public function deconnexion(): void
|
||||
{
|
||||
// Destruction de l'objet utilisateur
|
||||
unset($_SESSION['userObject']);
|
||||
|
@ -151,25 +144,30 @@ class SessionObject
|
|||
/**
|
||||
* Active le flag de suivi (vérification d'affichage de page avant envoi)
|
||||
*/
|
||||
public function setFlag()
|
||||
public function setFlag(): void
|
||||
{
|
||||
$_SESSION['flag'] = true;
|
||||
$_SESSION['flag'] = time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime le flag de suivi
|
||||
*/
|
||||
public function removeFlag()
|
||||
public function removeFlag(): void
|
||||
{
|
||||
unset($_SESSION['flag']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie le flag de suivi
|
||||
* @return boolean Suivi OK ?
|
||||
* Vérifie le flag de suivi (a été activé il y a plus d'une seconde)
|
||||
* @return bool Suivi OK ?
|
||||
*/
|
||||
public function checkFlag()
|
||||
public function checkFlag(): bool
|
||||
{
|
||||
return isset($_SESSION['flag']);
|
||||
$monRetour = false;
|
||||
// Au moins une seconde pour remplir le formulaire
|
||||
if (isset($_SESSION['flag']) && (time() - $_SESSION['flag']) > 1) {
|
||||
$monRetour = true;
|
||||
}
|
||||
return $monRetour;
|
||||
}
|
||||
}
|
||||
|
|
182
classes/Tor.class.php
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use JsonException;
|
||||
|
||||
/**
|
||||
* Fonctions relative à Tor
|
||||
*/
|
||||
class Tor
|
||||
{
|
||||
private const string IPV4 = 'IPv4';
|
||||
private const string IPV6 = 'IPv6';
|
||||
|
||||
/**
|
||||
* Mettre à jour la liste des adresses IP des noeuds de sortie Tor
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function updateListeExitNodes(): void
|
||||
{
|
||||
$torNodeList = file_get_contents(_TOR_EXIT_NODE_LIST_URL_);
|
||||
|
||||
// Ne mettre à jour que si on a des données
|
||||
if (!empty($torNodeList)) {
|
||||
// Récupération du dernier fichier
|
||||
$objJson = json_decode($torNodeList, false, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
$tabIP = [];
|
||||
$tabIP[self::IPV4] = [];
|
||||
$tabIP[self::IPV6] = [];
|
||||
|
||||
foreach ($objJson->relays as $unRelay) {
|
||||
// Adresse IP de sortie (IPv4 uniquement)
|
||||
// https://metrics.torproject.org/onionoo.html#details_relay_exit_addresses
|
||||
if (isset($unRelay->exit_addresses)) {
|
||||
foreach ($unRelay->exit_addresses as $uneIp) {
|
||||
$this->addToTab($uneIp, $tabIP);
|
||||
}
|
||||
}
|
||||
// Adresse IP sur lequel le noeud écoute (IPv4 + IPv6)
|
||||
// Lorsque exit_addresses incluera les IPv6, plus besoin de cette partie qui surbloque...
|
||||
if (isset($unRelay->or_addresses)) {
|
||||
foreach ($unRelay->or_addresses as $uneIp) {
|
||||
$this->addToTab($uneIp, $tabIP, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enregister le résultat sur le disque
|
||||
$retour = file_put_contents(_TOR_LISTE_IPV4_, json_encode($tabIP[self::IPV4], JSON_THROW_ON_ERROR));
|
||||
echo 'IPv4 : ' . $retour;
|
||||
$retour = file_put_contents(_TOR_LISTE_IPV6_, json_encode($tabIP[self::IPV6], JSON_THROW_ON_ERROR));
|
||||
echo '<br />IPv6 : ' . $retour;
|
||||
} else {
|
||||
// Envoyer un mail d'avertissement
|
||||
mail(_ADMINISTRATEUR_EMAIL_, '[' . _SITE_NAME_ . '] - Actualisation des noeuds Tor en erreur', 'Liste de noeuds récupérée : ' . var_export($torNodeList, true), 'From: ' . _ADMINISTRATEUR_EMAIL_);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoyer et ajouter une IP dans le tableau des adresses connues
|
||||
* @param string $ip @ IP à ajouter
|
||||
* @param string[] $tabIp Liste des addresses IP déjà connues
|
||||
* @param bool $withPort Le port est précisé (1.2.3.4:1234)
|
||||
*/
|
||||
private function addToTab(string $ip, array &$tabIp, bool $withPort = false): void
|
||||
{
|
||||
if (substr_count($ip, ':') > 1) {
|
||||
// C'est une IPv6
|
||||
|
||||
// Supprimer le port
|
||||
if ($withPort) {
|
||||
$ip = substr($ip, 0, strrpos($ip, ':'));
|
||||
}
|
||||
|
||||
// Supprimer les crochets de la notation [1234:5678::]
|
||||
$ip = str_replace(['[', ']'], '', $ip);
|
||||
|
||||
// Forcer la réécriture de l'IP
|
||||
$ip = inet_ntop(inet_pton($ip));
|
||||
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
$this->saveInTab($ip, $tabIp, self::IPV6);
|
||||
}
|
||||
} else {
|
||||
// C'est une IPv4
|
||||
|
||||
// Supprimer le port
|
||||
if ($withPort) {
|
||||
$ip = substr($ip, 0, strrpos($ip, ':'));
|
||||
}
|
||||
|
||||
// Valider l'IP et l'enregistrer si inconnue
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
$this->saveInTab($ip, $tabIp, self::IPV4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insérer dans le tableau une adresse sans faire de doublon
|
||||
* @param string $ip @ IP à ajouter
|
||||
* @param array $tabIp Liste des addresses IP déjà connues
|
||||
* @param string $typeIp IPv4 ou IPv6
|
||||
*/
|
||||
private function saveInTab(string $ip, array &$tabIp, string $typeIp): void
|
||||
{
|
||||
if (!in_array($ip, $tabIp[$typeIp], true)) {
|
||||
$tabIp[$typeIp][] = self::formatIp($ip);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatter une adresse IP
|
||||
* @param string $ip adresse IP à formatter
|
||||
* @return string adresse IP formattée
|
||||
*/
|
||||
private static function formatIp(string $ip): string
|
||||
{
|
||||
return inet_ntop(inet_pton($ip));
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si une IP correspond à un noeud de sortie Tor
|
||||
* @param string $ip
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkIp(string $ip): bool
|
||||
{
|
||||
$monRetour = true;
|
||||
|
||||
$ip = self::formatIp($ip);
|
||||
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
if (file_exists(_TOR_LISTE_IPV6_) && filesize(_TOR_LISTE_IPV6_) > 0) {
|
||||
try {
|
||||
$tabIp = json_decode(file_get_contents(_TOR_LISTE_IPV6_), true, 512, JSON_THROW_ON_ERROR);
|
||||
if (!in_array($ip, $tabIp, true)) {
|
||||
$monRetour = false;
|
||||
}
|
||||
} catch (JsonException $e) {
|
||||
// En cas d'erreur, par défaut, faire confiance à l'IP
|
||||
$monRetour = false;
|
||||
}
|
||||
}
|
||||
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
if (file_exists(_TOR_LISTE_IPV4_) && filesize(_TOR_LISTE_IPV4_) > 0) {
|
||||
try {
|
||||
$tabIp = json_decode(file_get_contents(_TOR_LISTE_IPV4_), true, 512, JSON_THROW_ON_ERROR);
|
||||
if (!in_array($ip, $tabIp, true)) {
|
||||
$monRetour = false;
|
||||
}
|
||||
} catch (JsonException $e) {
|
||||
// En cas d'erreur, par défaut, faire confiance à l'IP
|
||||
$monRetour = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -29,29 +29,30 @@ use ArrayObject;
|
|||
*/
|
||||
class UtilisateurObject
|
||||
{
|
||||
private $userName;
|
||||
private $password;
|
||||
private $email;
|
||||
private $dateInscription;
|
||||
private $ipInscription;
|
||||
private $level = self::LEVEL_GUEST;
|
||||
private $id = 0;
|
||||
private $isActif = 1;
|
||||
private $token;
|
||||
private string $userName = '';
|
||||
private string $password = '';
|
||||
private string $email = '';
|
||||
private string $dateInscription = '';
|
||||
private string $ipInscription = '';
|
||||
private int $level = self::LEVEL_GUEST;
|
||||
private int $id = 0;
|
||||
private bool $isActif = true;
|
||||
private string $token = '';
|
||||
|
||||
// Niveaux de droits
|
||||
public const LEVEL_GUEST = 0;
|
||||
public const LEVEL_USER = 1;
|
||||
public const LEVEL_ADMIN = 2;
|
||||
final public const int LEVEL_GUEST = 0;
|
||||
final public const int LEVEL_USER = 1;
|
||||
final public const int LEVEL_ADMIN = 2;
|
||||
|
||||
/**
|
||||
* @throws ImageHebergException
|
||||
*/
|
||||
public function __construct($userID = false)
|
||||
{
|
||||
// Utilisateur à charger
|
||||
if ($userID) {
|
||||
if (!$this->charger($userID)) {
|
||||
// Envoi d'une exception si l'utilisateur n'existe pas
|
||||
throw new Exception('Utilisateur ' . $userID . ' inexistant.');
|
||||
}
|
||||
if ($userID && !$this->charger($userID)) {
|
||||
// Envoi d'une exception si l'utilisateur n'existe pas
|
||||
throw new ImageHebergException('Utilisateur ' . $userID . ' inexistant.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +60,7 @@ class UtilisateurObject
|
|||
* Nom d'utilisateur avec htmlentities
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName()
|
||||
public function getUserName(): string
|
||||
{
|
||||
return htmlentities($this->userName);
|
||||
}
|
||||
|
@ -68,7 +69,7 @@ class UtilisateurObject
|
|||
* BDD - Nom d'utilisateur non htmlentities
|
||||
* @return string
|
||||
*/
|
||||
private function getUserNameBDD()
|
||||
private function getUserNameBDD(): string
|
||||
{
|
||||
return $this->userName;
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ class UtilisateurObject
|
|||
* Mot de passe
|
||||
* @return string
|
||||
*/
|
||||
private function getPassword()
|
||||
private function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
@ -86,35 +87,35 @@ class UtilisateurObject
|
|||
* Email
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail()
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date d'inscription
|
||||
* @return type
|
||||
* @return string
|
||||
*/
|
||||
private function getDateInscription()
|
||||
private function getDateInscription(): string
|
||||
{
|
||||
return $this->dateInscription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date d'inscription formatée
|
||||
* @return type
|
||||
* @return string
|
||||
*/
|
||||
public function getDateInscriptionFormate()
|
||||
public function getDateInscriptionFormate(): string
|
||||
{
|
||||
$phpdate = strtotime($this->getDateInscription());
|
||||
return date("d/m/Y", $phpdate);
|
||||
return date('d/m/Y', $phpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ IP d'inscription
|
||||
* @return string
|
||||
*/
|
||||
public function getIpInscription()
|
||||
public function getIpInscription(): string
|
||||
{
|
||||
return $this->ipInscription;
|
||||
}
|
||||
|
@ -123,52 +124,52 @@ class UtilisateurObject
|
|||
* Niveau de droits
|
||||
* @return int
|
||||
*/
|
||||
public function getLevel()
|
||||
public function getLevel(): int
|
||||
{
|
||||
return (int) $this->level;
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID en BDD
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
public function getId(): int
|
||||
{
|
||||
return (int) $this->id;
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utilisateur est actif ?
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsActif()
|
||||
public function getIsActif(): bool
|
||||
{
|
||||
return $this->isActif;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token associé au compte utilisateur
|
||||
* @return string|null
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utilisateur est actif ?
|
||||
* @param boolean $isActif
|
||||
* @param bool $isActif
|
||||
*/
|
||||
public function setIsActif($isActif)
|
||||
public function setIsActif(bool $isActif): void
|
||||
{
|
||||
$this->isActif = $isActif;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token lié à l'utilisateur
|
||||
* @param string|null $token
|
||||
* @param string $token
|
||||
*/
|
||||
public function setToken($token)
|
||||
public function setToken(string $token): void
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
|
@ -177,7 +178,7 @@ class UtilisateurObject
|
|||
* Nom d'utilisateur
|
||||
* @param string $userName
|
||||
*/
|
||||
public function setUserName($userName)
|
||||
public function setUserName(string $userName): void
|
||||
{
|
||||
$this->userName = $userName;
|
||||
}
|
||||
|
@ -186,7 +187,7 @@ class UtilisateurObject
|
|||
* Mot de passe
|
||||
* @param string $password
|
||||
*/
|
||||
private function setPassword($password)
|
||||
private function setPassword(string $password): void
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
|
@ -195,7 +196,7 @@ class UtilisateurObject
|
|||
* Mot de passe à crypter
|
||||
* @param string $password
|
||||
*/
|
||||
public function setPasswordToCrypt($password)
|
||||
public function setPasswordToCrypt(string $password): void
|
||||
{
|
||||
$this->password = password_hash($password, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
@ -204,16 +205,16 @@ class UtilisateurObject
|
|||
* Email
|
||||
* @param string $email
|
||||
*/
|
||||
public function setEmail($email)
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date d'inscription
|
||||
* @param type $dateInscription
|
||||
* @param string $dateInscription
|
||||
*/
|
||||
private function setDateInscription($dateInscription)
|
||||
private function setDateInscription(string $dateInscription): void
|
||||
{
|
||||
$this->dateInscription = $dateInscription;
|
||||
}
|
||||
|
@ -222,7 +223,7 @@ class UtilisateurObject
|
|||
* @ IP d'inscription
|
||||
* @param string $ipInscription
|
||||
*/
|
||||
private function setIpInscription($ipInscription)
|
||||
private function setIpInscription(string $ipInscription): void
|
||||
{
|
||||
$this->ipInscription = $ipInscription;
|
||||
}
|
||||
|
@ -231,7 +232,7 @@ class UtilisateurObject
|
|||
* Niveau de droits
|
||||
* @param int $level
|
||||
*/
|
||||
public function setLevel($level)
|
||||
public function setLevel(int $level): void
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
|
@ -240,7 +241,7 @@ class UtilisateurObject
|
|||
* ID en BDD
|
||||
* @param int $id
|
||||
*/
|
||||
private function setId($id)
|
||||
private function setId(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
@ -251,51 +252,48 @@ class UtilisateurObject
|
|||
* @param string $pwd Mot de passe associé
|
||||
* @return int ID de l'utilisateur (0 si identifiants invalides)
|
||||
*/
|
||||
private function verifierIdentifiants($user, $pwd)
|
||||
private function verifierIdentifiants(string $user, string $pwd): int
|
||||
{
|
||||
// Identifiants KO par défaut
|
||||
$monRetour = 0;
|
||||
|
||||
// Vérification de l'existance du login
|
||||
$req = MaBDD::getInstance()->prepare("SELECT * FROM membres WHERE login = :login");
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':login', $user, PDO::PARAM_STR);
|
||||
$req = MaBDD::getInstance()->prepare('SELECT * FROM membres WHERE login = :login');
|
||||
$req->bindValue(':login', $user);
|
||||
$req->execute();
|
||||
|
||||
// Je récupère les potentielles valeurs
|
||||
$values = $req->fetch();
|
||||
$resultat = $req->fetch();
|
||||
|
||||
// Si l'utilisateur existe
|
||||
if ($values !== false) {
|
||||
if ($resultat !== false) {
|
||||
// Faut-il mettre à jour le hash du mot de passe ?
|
||||
$updateHash = false;
|
||||
|
||||
// Est-ce un cas de compatibilité avec les anciens mots de passe ?
|
||||
if (substr($values->password, 0, 1) !== '$') {
|
||||
if (!str_starts_with($resultat->password, '$')) {
|
||||
// Les hash générés par crypt possédent un schème spécifique avec $ en premier chr
|
||||
// https://en.wikipedia.org/wiki/Crypt_(C)#Key_derivation_functions_supported_by_crypt
|
||||
if (hash_equals($values->password, hash('sha256', _GRAIN_DE_SEL_ . $pwd))) {
|
||||
if (hash_equals($resultat->password, hash('sha256', _GRAIN_DE_SEL_ . $pwd))) {
|
||||
// Ancien mot de passe => update hash du password ;-)
|
||||
$updateHash = true;
|
||||
// Identifiants matchent !
|
||||
$monRetour = $values->id;
|
||||
$monRetour = $resultat->id;
|
||||
}
|
||||
} else {
|
||||
} elseif (password_verify($pwd, $resultat->password)) {
|
||||
// Cas standard : comparaison du hash du mot de passe fourni avec celui stocké en base
|
||||
if (password_verify($pwd, $values->password)) {
|
||||
// => Faut-il mettre à jour le cryptage utilisé ?
|
||||
if (password_needs_rehash($values->password, PASSWORD_DEFAULT)) {
|
||||
$updateHash = true;
|
||||
}
|
||||
// Identifiants matchent !
|
||||
$monRetour = $values->id;
|
||||
// => Faut-il mettre à jour le chiffrement utilisé ?
|
||||
if (password_needs_rehash($resultat->password, PASSWORD_DEFAULT)) {
|
||||
$updateHash = true;
|
||||
}
|
||||
// Identifiants matchent !
|
||||
$monRetour = $resultat->id;
|
||||
}
|
||||
|
||||
// Mise à jour du hash si requis
|
||||
if ($updateHash) {
|
||||
$monUtilisateur = new UtilisateurObject();
|
||||
$monUtilisateur->charger($values->id);
|
||||
$monUtilisateur->charger($resultat->id);
|
||||
$monUtilisateur->setPasswordToCrypt($pwd);
|
||||
$monUtilisateur->modifier();
|
||||
}
|
||||
|
@ -307,9 +305,9 @@ class UtilisateurObject
|
|||
* Connexion d'un utilisateur : vérification & création de la session
|
||||
* @param string $user Utilisateur
|
||||
* @param string $pwd Mot de passe
|
||||
* @return boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function connexion($user, $pwd)
|
||||
public function connexion(string $user, string $pwd): bool
|
||||
{
|
||||
// Protection contre une attaque : on délaie un peu l'action
|
||||
usleep(500000);
|
||||
|
@ -331,9 +329,9 @@ class UtilisateurObject
|
|||
$maSession->setUserObject($this);
|
||||
|
||||
// J'enregistre en BDD la connexion réussie
|
||||
$req = MaBDD::getInstance()->prepare("INSERT INTO login (ip_login, date_login, pk_membres) VALUES (:ipLogin, NOW(), :pkMembres)");
|
||||
$req->bindValue(':ipLogin', $_SERVER['REMOTE_ADDR'], PDO::PARAM_STR);
|
||||
$req->bindValue(':pkMembres', $userID, PDO::PARAM_INT);
|
||||
$req = MaBDD::getInstance()->prepare('INSERT INTO login (remote_addr, date_action, membres_id) VALUES (:ipLogin, NOW(), :membresId)');
|
||||
$req->bindValue(':ipLogin', $_SERVER['REMOTE_ADDR']);
|
||||
$req->bindValue(':membresId', $userID, PDO::PARAM_INT);
|
||||
|
||||
$req->execute();
|
||||
}
|
||||
|
@ -345,33 +343,32 @@ class UtilisateurObject
|
|||
/**
|
||||
* Charge un utilisateur depuis la BDD
|
||||
* @param int $userID ID en BDD
|
||||
* @return boolean Utilisateur existant ?
|
||||
* @return bool Utilisateur existant ?
|
||||
*/
|
||||
private function charger($userID)
|
||||
private function charger(int $userID): bool
|
||||
{
|
||||
$monRetour = false;
|
||||
|
||||
// Je récupère les données en BDD
|
||||
$req = MaBDD::getInstance()->prepare("SELECT * FROM membres WHERE id = :id");
|
||||
/* @var $req PDOStatement */
|
||||
$req = MaBDD::getInstance()->prepare('SELECT * FROM membres WHERE id = :id');
|
||||
$req->bindValue(':id', $userID, PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
|
||||
// Je récupère les potentielles valeurs
|
||||
$values = $req->fetch();
|
||||
$resultat = $req->fetch();
|
||||
|
||||
// Si l'utilisateur n'existe pas... on retourne un UtilisateurObject vide
|
||||
if ($values !== false) {
|
||||
if ($resultat !== false) {
|
||||
// Je charge les informations de l'utilisateur (sauf password)
|
||||
$this->setId($userID);
|
||||
$this->setEmail($values->email);
|
||||
$this->setUserName($values->login);
|
||||
$this->setDateInscription($values->date_inscription);
|
||||
$this->setIpInscription($values->ip_inscription);
|
||||
$this->setLevel($values->lvl);
|
||||
$this->setPassword($values->password);
|
||||
$this->setIsActif($values->isActif);
|
||||
$this->setToken($values->token);
|
||||
$this->setEmail($resultat->email);
|
||||
$this->setUserName($resultat->login);
|
||||
$this->setDateInscription($resultat->date_action);
|
||||
$this->setIpInscription($resultat->remote_addr);
|
||||
$this->setLevel($resultat->lvl);
|
||||
$this->setPassword($resultat->password);
|
||||
$this->setIsActif($resultat->isActif);
|
||||
$this->setToken($resultat->token);
|
||||
|
||||
// Gestion du retour
|
||||
$monRetour = true;
|
||||
|
@ -383,17 +380,17 @@ class UtilisateurObject
|
|||
/**
|
||||
* Enregistrement (BDD) d'un utilisateur
|
||||
*/
|
||||
public function enregistrer()
|
||||
public function enregistrer(): void
|
||||
{
|
||||
$req = MaBDD::getInstance()->prepare("INSERT INTO membres (email, login, password, date_inscription, ip_inscription, lvl, isActif, token) VALUES (:email, :login, :password, NOW(), :ipInscription, :lvl, :isActif, :token)");
|
||||
$req->bindValue(':email', $this->getEmail(), PDO::PARAM_STR);
|
||||
$req->bindValue(':login', $this->getUserNameBDD(), PDO::PARAM_STR);
|
||||
$req->bindValue(':password', $this->getPassword(), PDO::PARAM_STR);
|
||||
$req = MaBDD::getInstance()->prepare('INSERT INTO membres (email, login, password, date_action, remote_addr, lvl, isActif, token) VALUES (:email, :login, :password, NOW(), :ipInscription, :lvl, :isActif, :token)');
|
||||
$req->bindValue(':email', $this->getEmail());
|
||||
$req->bindValue(':login', $this->getUserNameBDD());
|
||||
$req->bindValue(':password', $this->getPassword());
|
||||
// Date est définie par NOW()
|
||||
$req->bindValue(':ipInscription', $_SERVER['REMOTE_ADDR'], PDO::PARAM_STR);
|
||||
$req->bindValue(':ipInscription', $_SERVER['REMOTE_ADDR']);
|
||||
$req->bindValue(':lvl', $this->getLevel(), PDO::PARAM_INT);
|
||||
$req->bindValue(':isActif', $this->getIsActif(), PDO::PARAM_BOOL);
|
||||
$req->bindValue(':token', $this->getToken(), PDO::PARAM_STR);
|
||||
$req->bindValue(':token', $this->getToken());
|
||||
|
||||
$req->execute();
|
||||
}
|
||||
|
@ -401,15 +398,15 @@ class UtilisateurObject
|
|||
/**
|
||||
* Modifier (BDD) un utilisateur déjà existant
|
||||
*/
|
||||
public function modifier()
|
||||
public function modifier(): void
|
||||
{
|
||||
$req = MaBDD::getInstance()->prepare("UPDATE membres SET email = :email, login = :login, password = :password, lvl = :lvl, isActif = :isActif, token = :token WHERE id = :id");
|
||||
$req->bindValue(':email', $this->getEmail(), PDO::PARAM_STR);
|
||||
$req->bindValue(':login', $this->getUserNameBDD(), PDO::PARAM_STR);
|
||||
$req->bindValue(':password', $this->getPassword(), PDO::PARAM_STR);
|
||||
$req = MaBDD::getInstance()->prepare('UPDATE membres SET email = :email, login = :login, password = :password, lvl = :lvl, isActif = :isActif, token = :token WHERE id = :id');
|
||||
$req->bindValue(':email', $this->getEmail());
|
||||
$req->bindValue(':login', $this->getUserNameBDD());
|
||||
$req->bindValue(':password', $this->getPassword());
|
||||
$req->bindValue(':lvl', $this->getLevel(), PDO::PARAM_INT);
|
||||
$req->bindValue(':isActif', $this->getIsActif(), PDO::PARAM_BOOL);
|
||||
$req->bindValue(':token', $this->getToken(), PDO::PARAM_STR);
|
||||
$req->bindValue(':token', $this->getToken());
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
|
||||
$req->execute();
|
||||
|
@ -418,20 +415,20 @@ class UtilisateurObject
|
|||
/**
|
||||
* Suppression (BDD) d'un utilisateur
|
||||
*/
|
||||
public function supprimer()
|
||||
public function supprimer(): void
|
||||
{
|
||||
// Les images possédées
|
||||
$req = MaBDD::getInstance()->prepare("DELETE FROM possede WHERE pk_membres = :pkMembres");
|
||||
$req->bindValue(':pkMembres', $this->getId(), PDO::PARAM_INT);
|
||||
$req = MaBDD::getInstance()->prepare('DELETE FROM possede WHERE membres_id = :membresId');
|
||||
$req->bindValue(':membresId', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
|
||||
// Historique des logins
|
||||
$req = MaBDD::getInstance()->prepare("DELETE FROM login WHERE pk_membres = :pkMembres");
|
||||
$req->bindValue(':pkMembres', $this->getId(), PDO::PARAM_INT);
|
||||
$req = MaBDD::getInstance()->prepare('DELETE FROM login WHERE membres_id = :membresId');
|
||||
$req->bindValue(':membresId', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
|
||||
// Paramètres du compte
|
||||
$req = MaBDD::getInstance()->prepare("DELETE FROM membres WHERE id = :id");
|
||||
$req = MaBDD::getInstance()->prepare('DELETE FROM membres WHERE id = :id');
|
||||
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
}
|
||||
|
@ -439,83 +436,115 @@ class UtilisateurObject
|
|||
/**
|
||||
* Assigne une image à un utilisateur en BDD
|
||||
* @param ImageObject $imageObject
|
||||
* @throws ImageHebergException
|
||||
*/
|
||||
public function assignerImage($imageObject)
|
||||
public function assignerImage(ImageObject $imageObject): void
|
||||
{
|
||||
if ($this->getId() === 0) {
|
||||
throw new Exception("Aucun utilisateur n'est défini !");
|
||||
throw new ImageHebergException('Aucun utilisateur n\'est défini !');
|
||||
}
|
||||
|
||||
// Les images possédées
|
||||
$req = MaBDD::getInstance()->prepare("INSERT INTO possede (image_id, pk_membres) VALUES (:imageId, :pkMembres)");
|
||||
$req->bindValue(':imageId', $imageObject->getId(), PDO::PARAM_INT);
|
||||
$req->bindValue(':pkMembres', $this->getId(), PDO::PARAM_INT);
|
||||
$req = MaBDD::getInstance()->prepare('INSERT INTO possede (images_id, membres_id) VALUES (:imagesId, :membresId)');
|
||||
$req->bindValue(':imagesId', $imageObject->getId(), PDO::PARAM_INT);
|
||||
$req->bindValue(':membresId', $this->getId(), PDO::PARAM_INT);
|
||||
$req->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifier si un login est disponible pour enregistrement
|
||||
* @param type $login
|
||||
* @return boolean
|
||||
* @param string $login
|
||||
* @return bool
|
||||
*/
|
||||
public static function verifierLoginDisponible($login)
|
||||
public static function verifierLoginDisponible(string $login): bool
|
||||
{
|
||||
$req = MaBDD::getInstance()->prepare("SELECT * FROM membres WHERE login = :login");
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':login', $login, PDO::PARAM_STR);
|
||||
$req = MaBDD::getInstance()->prepare('SELECT * FROM membres WHERE login = :login');
|
||||
$req->bindValue(':login', $login);
|
||||
$req->execute();
|
||||
|
||||
// Par défaut le login est disponible
|
||||
$retour = true;
|
||||
$monRetour = true;
|
||||
|
||||
// Si j'ai un résultat...
|
||||
if ($req->fetch()) {
|
||||
// Le retour est négatif
|
||||
$retour = false;
|
||||
$monRetour = false;
|
||||
}
|
||||
|
||||
return $retour;
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifier si un email est disponible pour enregistrement
|
||||
* @param string $email
|
||||
* @return bool
|
||||
*/
|
||||
public static function verifierEmailDisponible(string $email): bool
|
||||
{
|
||||
$req = MaBDD::getInstance()->prepare('SELECT * FROM membres WHERE email = :email');
|
||||
$req->bindValue(':email', strtolower($email));
|
||||
$req->execute();
|
||||
|
||||
// Par défaut l'email est disponible
|
||||
$monRetour = true;
|
||||
|
||||
// Si j'ai un résultat...
|
||||
if ($req->fetch()) {
|
||||
// Le retour est négatif
|
||||
$monRetour = false;
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie que l'utilisateur à le droit d'afficher la page et affiche un EM au cas où
|
||||
* @param type $levelRequis
|
||||
* @param int $levelRequis Niveau de droit minimum requis
|
||||
* @param bool $dieIfNotGranted Arrêter le script si le niveau de droit n'est pas atteint
|
||||
* @return void|bool
|
||||
*/
|
||||
public static function checkAccess($levelRequis)
|
||||
public static function checkAccess(int $levelRequis, bool $dieIfNotGranted = true)
|
||||
{
|
||||
$monRetour = false;
|
||||
|
||||
$monUser = new SessionObject();
|
||||
if ($monUser->verifierDroits($levelRequis) === false) {
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
require _TPL_TOP_;
|
||||
echo "<h1 class=\"mb-3\">Accès refusé</h1>";
|
||||
echo "<p>Désolé, vous n'avez pas le droit d'accèder à cette page.</p>";
|
||||
require _TPL_BOTTOM_;
|
||||
die();
|
||||
// Arrêter le script...
|
||||
if ($dieIfNotGranted) {
|
||||
header('HTTP/2 403 Forbidden');
|
||||
require _TPL_TOP_;
|
||||
echo '<h1 class="mb-3">Accès refusé</h1>';
|
||||
echo '<p>Désolé, vous n\'avez pas le droit d\'accèder à cette page.</p>';
|
||||
require _TPL_BOTTOM_;
|
||||
die();
|
||||
}
|
||||
} else {
|
||||
$monRetour = true;
|
||||
}
|
||||
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toutes les images appartenant à un utilisateur
|
||||
* @param type $userId ID de l'user en question
|
||||
* @return \ArrayObject new_name image
|
||||
* @return ArrayObject new_name image
|
||||
*/
|
||||
public function getImages()
|
||||
public function getImages(): ArrayObject
|
||||
{
|
||||
// Toutes les images
|
||||
$req = MaBDD::getInstance()->prepare("SELECT new_name FROM possede, images WHERE id = image_id AND pk_membres = :pkMembres ");
|
||||
/* @var $req PDOStatement */
|
||||
$req->bindValue(':pkMembres', $this->getId(), PDO::PARAM_INT);
|
||||
$req = MaBDD::getInstance()->prepare('SELECT new_name FROM possede, images WHERE id = images_id AND membres_id = :membresId ');
|
||||
$req->bindValue(':membresId', $this->getId(), PDO::PARAM_INT);
|
||||
|
||||
// Exécution de la requête
|
||||
$req->execute();
|
||||
|
||||
$retour = new ArrayObject();
|
||||
$monRetour = new ArrayObject();
|
||||
// Pour chaque résultat retourné
|
||||
foreach ($req->fetchAll() as $value) {
|
||||
// J'ajoute le nom de l'image
|
||||
$retour->append($value->new_name);
|
||||
$monRetour->append($value->new_name);
|
||||
}
|
||||
|
||||
return $retour;
|
||||
return $monRetour;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,50 +24,75 @@
|
|||
*/
|
||||
/* Base de données */
|
||||
// Serveur de base de données
|
||||
define('_BDD_HOST_', 'xxx');
|
||||
const _BDD_HOST_ = 'xxx';
|
||||
// Utilisateur SQL
|
||||
define('_BDD_USER_', 'xxx');
|
||||
const _BDD_USER_ = 'xxx';
|
||||
// Mot de passe SQL
|
||||
define('_BDD_PASS_', 'xxx');
|
||||
const _BDD_PASS_ = 'xxx';
|
||||
// Nom de la base de données
|
||||
define('_BDD_NAME_', 'xxx');
|
||||
const _BDD_NAME_ = 'xxx';
|
||||
|
||||
|
||||
/* Système de fichiers */
|
||||
// Emplacement de votre site sur le système de fichiers de votre hébergeur
|
||||
define('_PATH_', '/path/to/example.com/');
|
||||
const _PATH_ = '/path/to/example.com/';
|
||||
|
||||
|
||||
/* A propos de l'outil */
|
||||
// Nom affiché du service
|
||||
define('_SITE_NAME_', 'monSite');
|
||||
const _SITE_NAME_ = 'monSite';
|
||||
// URL du site
|
||||
define('_BASE_URL_', 'www.example.com/');
|
||||
const _BASE_URL_ = 'www.example.com/';
|
||||
// Administrateur du site
|
||||
define('_ADMINISTRATEUR_NOM_', 'John DOE');
|
||||
const _ADMINISTRATEUR_NOM_ = 'John DOE';
|
||||
// Site web de l'administrateur
|
||||
define('_ADMINISTRATEUR_SITE_', '//www.example.com/');
|
||||
const _ADMINISTRATEUR_SITE_ = '//www.example.com/';
|
||||
// Mail de l'administrateur (non affiché)
|
||||
define('_ADMINISTRATEUR_EMAIL_', 'john.doe@example.com');
|
||||
const _ADMINISTRATEUR_EMAIL_ = 'john.doe@example.com';
|
||||
|
||||
|
||||
/* Informations légales */
|
||||
// Hébergeur du site
|
||||
define('_HEBERGEUR_NOM_', 'OVH');
|
||||
const _HEBERGEUR_NOM_ = 'HOSTING';
|
||||
// Site web de l'hébergeur
|
||||
define('_HEBERGEUR_SITE_', '//www.ovh.com');
|
||||
const _HEBERGEUR_SITE_ = '//www.example.com';
|
||||
|
||||
|
||||
/* Configurations spécifiques de l'outil */
|
||||
// Poids maximal des fichiers
|
||||
define('_IMAGE_POIDS_MAX_', 5242880);
|
||||
const _IMAGE_POIDS_MAX_ = 5242880;
|
||||
// Délai de conservation d'une image jamais affichée (en jours)
|
||||
define('_DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_', 7);
|
||||
const _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ = 7;
|
||||
// Délai depuis le dernier affichage d'une image avant de la supprimer (en jours)
|
||||
define('_DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_', 365);
|
||||
const _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ = 365;
|
||||
// Volume maximal de stockage d'images (en Go)
|
||||
define('_QUOTA_MAXIMAL_IMAGES_GO_', 90);
|
||||
const _QUOTA_MAXIMAL_IMAGES_GO_ = 90;
|
||||
// Affichage des messages d'erreur
|
||||
define('_DEBUG_', true);
|
||||
const _DEBUG_ = false;
|
||||
// Délai de conservation des comptes jamais utilisés (en jours)
|
||||
const _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ = 30;
|
||||
|
||||
|
||||
/* Gestion des abus */
|
||||
// Nombre d'affichages par jour à partir duquel une image est suspecte
|
||||
const _ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ = 1500;
|
||||
// Nombre d'affichages par jour à partir duquel une image est automatiquement bloquée
|
||||
const _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ = 100000;
|
||||
// Nombre d'affichages par jour à partir duquel une image est clairement abusive;
|
||||
const _ABUSE_NB_AFFICHAGES_PAR_JOUR_ABUSIF_ = 10 * _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_;
|
||||
// Division des seuils d'abus si une image est considérée comme suspecte
|
||||
const _ABUSE_DIVISION_SEUILS_SI_SUSPECT_ = 2;
|
||||
|
||||
// Désactiver l'envoi d'images depuis un noeud de sortie Tor
|
||||
const _TOR_DISABLE_UPLOAD_ = true;
|
||||
// Désactiver l'envoi d'images au bout de x images bloquées (mettre 0 pour ne pas l'activer)
|
||||
const _ABUSE_DISABLE_UPLOAD_AFTER_X_IMAGES_ = 100;
|
||||
|
||||
// User-Agent pour lesquels bloquer les images
|
||||
const _ABUSE_DISABLE_PICS_WHEN_USERE_AGENT_ = ['someUserAgentNumberOne', 'AnoterUserAgentNumberTwo'];
|
||||
|
||||
// Clef pour la récupération des données pour l'entraînement du module d'IA
|
||||
const _KEY_FOR_IA_TRAINING_ = '';
|
||||
|
||||
/**
|
||||
* FIN DES CHAMPS A CONFIGURER
|
||||
|
@ -77,11 +102,11 @@ define('_DEBUG_', true);
|
|||
*/
|
||||
// Salt pour les mots de passe
|
||||
// Legacy - n'est plus requis !!
|
||||
define('_GRAIN_DE_SEL_', 'xxx');
|
||||
const _GRAIN_DE_SEL_ = 'xxx';
|
||||
/**
|
||||
* FIN DES CHAMPS A COMPLETER UNIQUEMENT SI VOUS AVEZ UNE VERSION ANTERIEURE A v2.0.4
|
||||
*/
|
||||
// Désactivation des tests Tests TRAVIS-CI
|
||||
define('_PHPUNIT_', false);
|
||||
const _PHPUNIT_ = false;
|
||||
|
||||
require _PATH_ . 'config/image-heberg.php';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,25 +21,35 @@
|
|||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
error_reporting(E_ALL);
|
||||
// Avoir le détail des paramètres des méthodes dans les stack traces
|
||||
ini_set('zend.exception_string_param_max_len', 1000000);
|
||||
|
||||
if (_DEBUG_) {
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
}
|
||||
if (!_PHPUNIT_) {
|
||||
/**
|
||||
* Supprime des informations sensibles du log d'erreur
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
function exception_handler_cleaner(string $value): string
|
||||
{
|
||||
return str_replace([_BDD_HOST_, _BDD_NAME_, _BDD_USER_, _BDD_PASS_, _PATH_], 'xxx', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestion des exceptions de l'application
|
||||
* @param Exception $exception
|
||||
* @param Throwable $exception
|
||||
*/
|
||||
function exception_handler($exception)
|
||||
function exception_handler(Throwable $exception): void
|
||||
{
|
||||
/* @var $exception Exception */
|
||||
if (_DEBUG_) {
|
||||
// Afficher l'erreur en masquant les informations sensibles
|
||||
echo '<pre>';
|
||||
print_r($exception->getMessage());
|
||||
print_r(exception_handler_cleaner($exception->getMessage()));
|
||||
echo '<br /><br /><hr /><br />';
|
||||
print_r($exception->getTraceAsString());
|
||||
print_r(exception_handler_cleaner($exception->getTraceAsString()));
|
||||
echo '</pre>';
|
||||
} else {
|
||||
echo 'Une erreur a été rencontrée';
|
||||
|
@ -49,34 +59,55 @@ if (!_PHPUNIT_) {
|
|||
* Envoi d'un mail avec le détail de l'erreur à l'administrateur
|
||||
*/
|
||||
// Adresse expediteur
|
||||
$headers = 'From: ' . _ADMINISTRATEUR_EMAIL_ . "\n";
|
||||
$headers = 'From: ' . _ADMINISTRATEUR_EMAIL_;
|
||||
// Adresse de retour
|
||||
$headers .= 'Reply-To: ' . _ADMINISTRATEUR_EMAIL_ . "\n";
|
||||
$headers .= PHP_EOL . 'Reply-To: ' . _ADMINISTRATEUR_EMAIL_;
|
||||
// Agent mail
|
||||
$headers .= 'X-Mailer: ' . _SITE_NAME_ . ' script at ' . _URL_ . "\n";
|
||||
$headers .= PHP_EOL . 'X-Mailer: ' . _SITE_NAME_ . ' script at ' . _URL_;
|
||||
// Date
|
||||
$headers .= 'Date: ' . date('D, j M Y H:i:s +0200') . "\n";
|
||||
$message = $exception->getMessage() . "\r\n" . $exception->getTraceAsString();
|
||||
$message .= "\r\nURL : " . $_SERVER['REQUEST_URI'];
|
||||
if (isset($_SERVER['HTTP_REFERER'])) {
|
||||
$message .= "\r\nHTTP REFERER : " . $_SERVER['HTTP_REFERER'];
|
||||
}
|
||||
$message .= "\r\nHTTP USER AGENT : " . $_SERVER['HTTP_USER_AGENT'];
|
||||
$message .= "\r\nREMOTE ADDR : " . $_SERVER['REMOTE_ADDR'];
|
||||
$headers .= PHP_EOL . 'Date: ' . date('D, j M Y H:i:s +0200');
|
||||
$message = PHP_EOL . exception_handler_cleaner($exception->getMessage()) . PHP_EOL . exception_handler_cleaner($exception->getTraceAsString());
|
||||
$message .= PHP_EOL . 'URL : ' . ($_SERVER['REQUEST_URI'] ?? '');
|
||||
$message .= PHP_EOL . 'HTTP REFERER : ' . ($_SERVER['HTTP_REFERER'] ?? '');
|
||||
$message .= PHP_EOL . 'HTTP USER AGENT : ' . ($_SERVER['HTTP_USER_AGENT'] ?? '');
|
||||
$message .= PHP_EOL . 'REMOTE ADDR : ' . ($_SERVER['REMOTE_ADDR'] ?? '');
|
||||
$message .= PHP_EOL . 'DATE : ' . date('Y-m-d H:i:s');
|
||||
|
||||
mail(_ADMINISTRATEUR_EMAIL_, '[' . _URL_ . '] Erreur rencontrée', $message, $headers);
|
||||
mail(_ADMINISTRATEUR_EMAIL_, '[' . _SITE_NAME_ . '] - Erreur rencontrée', $message, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestions des erreurs dans l'application
|
||||
* @param int $errno Niveau d'erreur
|
||||
* @param string $errstr Message d'erreur
|
||||
* @param string $errfile Fichier où à lieu l'erreur
|
||||
* @param int $errline Ligne concernée
|
||||
* @return void
|
||||
*/
|
||||
function error_handler(int $errno, string $errstr, string $errfile, int $errline): void
|
||||
{
|
||||
$monException = new ImageHebergException();
|
||||
$monException->define($errstr, $errno, $errfile, $errline);
|
||||
|
||||
exception_handler($monException);
|
||||
}
|
||||
|
||||
set_exception_handler('ImageHeberg\exception_handler');
|
||||
set_error_handler('ImageHeberg\error_handler');
|
||||
}
|
||||
|
||||
// Répertoires
|
||||
/**
|
||||
* Répertoires
|
||||
*/
|
||||
define('_REPERTOIRE_IMAGE_', 'files/');
|
||||
define('_REPERTOIRE_MINIATURE_', _REPERTOIRE_IMAGE_ . 'thumbs/');
|
||||
define('_REPERTOIRE_ADMIN_', 'admin/');
|
||||
define('_REPERTOIRE_MEMBRE_', 'membre/');
|
||||
define('_REPERTOIRE_CONFIG_', 'config/');
|
||||
|
||||
// URL
|
||||
/**
|
||||
* URL
|
||||
*/
|
||||
define('_URL_', 'http://' . _BASE_URL_);
|
||||
define('_URL_HTTPS_', 'https://' . _BASE_URL_);
|
||||
define('_URL_SANS_SCHEME_', '//' . _BASE_URL_);
|
||||
|
@ -86,37 +117,64 @@ define('_URL_IMAGES_', _URL_ . _REPERTOIRE_IMAGE_);
|
|||
define('_URL_MINIATURES_', _URL_ . _REPERTOIRE_MINIATURE_);
|
||||
define('_URL_CONFIG_', _URL_HTTPS_ . _REPERTOIRE_CONFIG_);
|
||||
|
||||
// Système de fichiers
|
||||
/**
|
||||
* Système de fichiers
|
||||
*/
|
||||
define('_PATH_IMAGES_', _PATH_ . _REPERTOIRE_IMAGE_);
|
||||
define('_PATH_MINIATURES_', _PATH_ . _REPERTOIRE_MINIATURE_);
|
||||
define('_PATH_ADMIN_', _PATH_ . _REPERTOIRE_ADMIN_);
|
||||
define('_PATH_TESTS_IMAGES_', _PATH_ . '__tests/images/');
|
||||
define('_PATH_TESTS_IMAGES_', _PATH_ . '__tests/images/'); // Images pour les tests
|
||||
define('_PATH_TESTS_IMAGES_A_IMPORTER_', _PATH_TESTS_IMAGES_ . 'aImporter/'); // Images devant déjà être importées avant d'exécurer les tests
|
||||
define('_PATH_TESTS_OUTPUT_', _PATH_ . '__tests/output/');
|
||||
define('_TPL_TOP_', _PATH_ . 'template/templateV2Top.php');
|
||||
define('_TPL_BOTTOM_', _PATH_ . 'template/templateV2Bottom.php');
|
||||
|
||||
// Fonction de chargement des classes en cas de besoin
|
||||
spl_autoload_register(function ($class) {
|
||||
// Suppression du namespace
|
||||
$class = str_replace('ImageHeberg\\', "", $class);
|
||||
|
||||
// Code pour TRAVIS
|
||||
$charger = true;
|
||||
|
||||
// Code spécifique Travis : pas de chargement des classes de PHPUnit
|
||||
if (_PHPUNIT_ && (strpos($class, "PHPUnit") !== false || strpos($class, "Composer") !== false)) {
|
||||
$charger = false;
|
||||
spl_autoload_register(static function ($class) {
|
||||
// Ne pas faire d'erreur pour les classes gérées par l'autoloader de PHPUnit
|
||||
if (_PHPUNIT_ && str_starts_with($class, 'PHPUnit')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($charger) {
|
||||
require _PATH_ . 'classes/' . $class . '.class.php';
|
||||
// Suppression du namespace
|
||||
$class = str_replace('ImageHeberg\\', '', $class);
|
||||
if (str_contains($class, 'Helper')) {
|
||||
// Helper par exemple
|
||||
$file = _PATH_ . 'classes/' . $class . '.php';
|
||||
} else {
|
||||
// Classe instantiable
|
||||
$file = _PATH_ . 'classes/' . $class . '.class.php';
|
||||
}
|
||||
|
||||
// Si le fichier existe...
|
||||
if (file_exists($file)) {
|
||||
require $file;
|
||||
} elseif (_PHPUNIT_) {
|
||||
echo 'spl_autoload_register() - Impossible de charger : ' . $file . ' (' . $class . ')' . PHP_EOL;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Paramètres divers pour les images
|
||||
*/
|
||||
// Gestion de la mémoire
|
||||
define('_FUDGE_FACTOR_', 1.8);
|
||||
define('_IMAGE_DIMENSION_MAX_', Outils::getMaxDimension());
|
||||
define('_IMAGE_DIMENSION_MAX_', HelperImage::getMaxDimension());
|
||||
|
||||
// Images spécifiques
|
||||
define('_IMAGE_404_', '_image_404.png');
|
||||
define('_IMAGE_BAN_', '_image_banned.png');
|
||||
|
||||
// Dimensions des apeçus dans l'espace membre
|
||||
define('_SIZE_PREVIEW_', 256);
|
||||
|
||||
// Types d'images gérés
|
||||
define('_ACCEPTED_EXTENSIONS_', ['jpg', 'png', 'gif', 'webp']);
|
||||
define('_ACCEPTED_MIME_TYPE_', [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_WEBP]);
|
||||
|
||||
/**
|
||||
* Tor
|
||||
*/
|
||||
// URL de l'API Tor
|
||||
define('_TOR_EXIT_NODE_LIST_URL_', 'https://onionoo.torproject.org/details?flag=exit');
|
||||
define('_TOR_LISTE_IPV4_', _PATH_ . _REPERTOIRE_IMAGE_ . 'z_cache/ipv4.txt');
|
||||
define('_TOR_LISTE_IPV6_', _PATH_ . _REPERTOIRE_IMAGE_ . 'z_cache/ipv6.txt');
|
||||
|
|
35
contact.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -22,23 +22,25 @@
|
|||
namespace ImageHeberg;
|
||||
|
||||
require 'config/config.php';
|
||||
require _TPL_TOP_;
|
||||
|
||||
// Anti flood
|
||||
$maSession = new SessionObject();
|
||||
|
||||
require _TPL_TOP_;
|
||||
|
||||
// En cas de validation du formulaire
|
||||
if (isset($_POST['Submit']) && $maSession->checkFlag()) {
|
||||
// Vérification du bon format de l'adresse mail
|
||||
if (filter_var($_POST['userMail'], FILTER_VALIDATE_EMAIL) !== false) {
|
||||
// Je complète le message avec l'IP de mon émeteur
|
||||
$message = $_POST['userMessage'];
|
||||
$message .= "\r\n\r\n ---------------------------------------------";
|
||||
$message .= "\r\n\r\n IP : " . $_SERVER['REMOTE_ADDR'];
|
||||
$message .= "\r\n\r\n BROWSER : " . $_SERVER['HTTP_USER_AGENT'];
|
||||
$message .= PHP_EOL . '---------------------------------------------';
|
||||
$message .= PHP_EOL . 'IP : ' . $_SERVER['REMOTE_ADDR'];
|
||||
$message .= PHP_EOL . 'BROWSER : ' . $_SERVER['HTTP_USER_AGENT'];
|
||||
$message .= PHP_EOL . 'DATE : ' . date('Y-m-d H:i:s');
|
||||
|
||||
// Tout va bien, on envoit un mail
|
||||
mail(_ADMINISTRATEUR_EMAIL_, "[" . _SITE_NAME_ . "] - Formulaire de contact", $message, "From: " . $_POST['userMail']);
|
||||
mail(_ADMINISTRATEUR_EMAIL_, '[' . _SITE_NAME_ . '] - Formulaire de contact', $message, 'From: ' . $_POST['userMail']);
|
||||
$maSession->removeFlag();
|
||||
|
||||
// Retour utilisateur
|
||||
|
@ -47,27 +49,24 @@ if (isset($_POST['Submit']) && $maSession->checkFlag()) {
|
|||
// Adresse mail invalide
|
||||
echo '<div class = "alert alert-danger">Votre adresse mail n\'est pas valide !<br /><pre>' . $_POST['userMail'] . '</pre></div>';
|
||||
}
|
||||
} else {
|
||||
// Premier affichage de la page
|
||||
if (!isset($_POST['Submit'])) {
|
||||
// Activation de la protection robot
|
||||
$maSession->setFlag();
|
||||
}
|
||||
} elseif (!isset($_POST['Submit'])) {
|
||||
// Premier affichage de la page => activation de la protection robot
|
||||
$maSession->setFlag();
|
||||
}
|
||||
?>
|
||||
<?php if ($maSession->checkFlag()) : ?>
|
||||
<?php if (!isset($_POST['Submit']) || $maSession->checkFlag()) : ?>
|
||||
<h1 class="mb-3"><small>Contacter l'administrateur du service - <?= _ADMINISTRATEUR_NOM_ ?></small></h1>
|
||||
<form method="post">
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="email" class="form-control" name="userMail" id="userMail" required="required" value="<?= (isset($_POST['userMail'])) ? $_POST['userMail'] : '' ?>">
|
||||
<label for="userMail" >Votre adresse courriel</label>
|
||||
<input type="email" class="form-control" name="userMail" id="userMail" required="required" value="<?= $_POST['userMail'] ?? '' ?>">
|
||||
<label for="userMail">Votre adresse courriel</label>
|
||||
<div class="form-text">Sera utilisée uniquement pour vous apporter une réponse.</div>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<textarea class="form-control" name="userMessage" id="userMessage" required="required"><?= (isset($_POST['userMessage'])) ? $_POST['userMessage'] : '' ?></textarea>
|
||||
<textarea class="form-control" name="userMessage" id="userMessage" required="required"><?= $_POST['userMessage'] ?? '' ?></textarea>
|
||||
<label for="userMessage">Votre message</label>
|
||||
</div>
|
||||
<button type="submit" name="Submit" class="btn btn-success">Envoyer</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
<?php endif; ?>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
108
cron/abuse.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
use ArrayObject;
|
||||
use Exception;
|
||||
|
||||
/*
|
||||
* Vérifier les images avec des comportements suspects
|
||||
*/
|
||||
// Peut être appelé par displayPics.php -> ne pas recharger la config
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
/**
|
||||
* Met en forme pour un mail une liste d'images
|
||||
* @param ArrayObject $listeImages
|
||||
* @param string $titre Titre de la catégorie à indiquer dans le mail
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function formatageMailListeImages(ArrayObject $listeImages, string $titre): string
|
||||
{
|
||||
$monRetour = '';
|
||||
if (count($listeImages) > 0) {
|
||||
$monRetour = $titre . ' : (' . count($listeImages) . ')' . PHP_EOL;
|
||||
foreach ((array)$listeImages as $value) {
|
||||
$monImage = new ImageObject($value);
|
||||
$monRetour .= ' -> ' . $monImage->getURL(true) . '?forceDisplay=1 ("' . $monImage->getNomOriginalFormate() . '") : ' . $monImage->getNbViewTotal() . ' affichages (' . $monImage->getNbViewPerDay() . '/jour) - envoyée le ' . $monImage->getDateEnvoiFormatee() . ' par ' . $monImage->getIpEnvoi() . ' - dernier affichage le ' . $monImage->getLastViewFormate() . PHP_EOL;
|
||||
}
|
||||
$monRetour .= '...done' . PHP_EOL;
|
||||
}
|
||||
return $monRetour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bloquer des images
|
||||
* @param ArrayObject $listeImages liste d'images à bloquer
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
function bloquerImage(ArrayObject $listeImages): void
|
||||
{
|
||||
foreach ((array)$listeImages as $value) {
|
||||
$monImage = new ImageObject($value);
|
||||
$monImage->setSignalee(true);
|
||||
$monImage->sauver();
|
||||
}
|
||||
}
|
||||
|
||||
$contenu = '';
|
||||
// Tracer l'image ayant généré l'appel au cron
|
||||
if (!empty($_SERVER['REQUEST_URI'])) {
|
||||
$contenu .= 'Requête ayant généré le cron : ' . $_SERVER['REQUEST_URI'] . PHP_EOL;
|
||||
}
|
||||
// Liste des images signalées
|
||||
$listeImages = HelperAdmin::getImagesSignalees();
|
||||
$contenu .= formatageMailListeImages($listeImages, 'Images signalées');
|
||||
|
||||
// Liste des images avec un ratio d'affichage important
|
||||
$listeImages = HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_);
|
||||
$contenu .= formatageMailListeImages($listeImages, 'Images qui sont beaucoup affichées (>' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ . '/jour)');
|
||||
|
||||
// Liste des images SUSPECTES avec un ratio d'affichage important
|
||||
$listeImages = HelperAdmin::getImagesTropAffichees((_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_), true);
|
||||
$contenu .= formatageMailListeImages($listeImages, 'Images SUSPECTES qui sont beaucoup affichées (>' . (_ABUSE_NB_AFFICHAGES_PAR_JOUR_WARNING_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_) . '/jour)');
|
||||
|
||||
// Liste des images avec un ratio d'affichage abusif
|
||||
$listeImages = HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_);
|
||||
bloquerImage($listeImages);
|
||||
$contenu .= formatageMailListeImages($listeImages, 'Blocage des images qui abusent (>' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ . '/jour)');
|
||||
|
||||
// Liste des images SUSPECTES avec un ratio d'affichage abusif
|
||||
$listeImages = HelperAdmin::getImagesTropAffichees((_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_), true);
|
||||
bloquerImage($listeImages);
|
||||
$contenu .= formatageMailListeImages($listeImages, 'Blocage des images SUSPECTES qui abusent (>' . (_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_) . '/jour)');
|
||||
|
||||
// Liste des images suspectes
|
||||
$listeImages = HelperAdmin::getImagesPotentiellementIndesirables();
|
||||
$contenu .= formatageMailListeImages($listeImages, 'Images suspectes');
|
||||
|
||||
// Liste des images abusant clairement
|
||||
$listeImages = HelperAdmin::getImagesTropAffichees(_ABUSE_NB_AFFICHAGES_PAR_JOUR_ABUSIF_, false, true, true);
|
||||
$contenu .= formatageMailListeImages($listeImages, 'Images qui abusent du service (>' . _ABUSE_NB_AFFICHAGES_PAR_JOUR_ABUSIF_ . '/jour)');
|
||||
|
||||
|
||||
if (!empty($contenu)) {
|
||||
// Envoyer une notification à l'admin
|
||||
mail(_ADMINISTRATEUR_EMAIL_, '[' . _SITE_NAME_ . '] - Gestion des abus', $contenu, 'From: ' . _ADMINISTRATEUR_EMAIL_);
|
||||
}
|
39
cron/cleanAccounts.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
/*
|
||||
* Suppression des comptes obsolètes
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../config/config.php';
|
||||
|
||||
// Effacer les comptes jamais utilisés
|
||||
echo 'Suppression des comptes jamais utilisés ' . _DELAI_EFFACEMENT_COMPTES_JAMAIS_UTILISES_ . ' jours après leur création' . PHP_EOL;
|
||||
$listeComptes = HelperAdmin::getUnusedAccounts();
|
||||
foreach ((array)$listeComptes as $value) {
|
||||
// Je crée mon objet et lance la suppression
|
||||
$monUtilisateur = new UtilisateurObject($value);
|
||||
echo ' -> ' . $monUtilisateur->getEmail() . ' - créé le ' . $monUtilisateur->getDateInscriptionFormate() . ' via IP ' . $monUtilisateur->getIpInscription() . PHP_EOL;
|
||||
$monUtilisateur->supprimer();
|
||||
}
|
||||
echo '...done' . PHP_EOL;
|
50
cron/cleanImages.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
/*
|
||||
* Suppression des images obsolètes
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../config/config.php';
|
||||
|
||||
// Effacer les fichiers jamais affichées
|
||||
echo 'Suppression des images jamais affichées depuis ' . _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ . ' jours' . PHP_EOL;
|
||||
$listeImages = HelperAdmin::getNeverUsedFiles();
|
||||
foreach ((array)$listeImages as $value) {
|
||||
// Je crée mon objet et lance la suppression
|
||||
$monImage = new ImageObject($value);
|
||||
echo ' -> ' . $monImage->getNomNouveau() . ' (envoi le ' . $monImage->getDateEnvoiFormatee() . ')' . PHP_EOL;
|
||||
$monImage->supprimer();
|
||||
}
|
||||
echo '...done' . PHP_EOL;
|
||||
|
||||
// Effacer les fichiers inactifs
|
||||
echo 'Suppression des images non affichées depuis ' . _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ . ' jours' . PHP_EOL;
|
||||
$listeImages = HelperAdmin::getUnusedFiles();
|
||||
foreach ((array)$listeImages as $value) {
|
||||
// Je crée mon objet et lance la suppression
|
||||
$monImage = new ImageObject($value);
|
||||
echo ' -> ' . $monImage->getNomNouveau() . ' (dernier affichage le ' . $monImage->getLastViewFormate() . ')' . PHP_EOL;
|
||||
$monImage->supprimer();
|
||||
}
|
||||
echo '...done' . PHP_EOL;
|
34
cron/updateTorIp.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
* image-heberg.fr is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* image-heberg.fr is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
/*
|
||||
* Mise à jour des adresses IP des noeuds de sortie TOR
|
||||
*/
|
||||
|
||||
require __DIR__ . '/../config/config.php';
|
||||
|
||||
if (_TOR_DISABLE_UPLOAD_) {
|
||||
$objTor = new Tor();
|
||||
$objTor->updateListeExitNodes();
|
||||
}
|
||||
echo '...done' . PHP_EOL;
|
161
database.sql
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -21,98 +21,131 @@
|
|||
-- Structure de la table `images`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `images` (
|
||||
`id` int(20) NOT NULL AUTO_INCREMENT,
|
||||
`ip_envoi` text NOT NULL,
|
||||
`date_envoi` datetime NULL DEFAULT NULL,
|
||||
`old_name` text NOT NULL,
|
||||
`new_name` text NOT NULL,
|
||||
`size` int(11) NOT NULL,
|
||||
`height` int(11) NOT NULL,
|
||||
`width` int(11) NOT NULL,
|
||||
`last_view` date NULL DEFAULT NULL,
|
||||
`nb_view_v4` int(11) NOT NULL DEFAULT '0',
|
||||
`nb_view_v6` int(11) NOT NULL DEFAULT '0',
|
||||
`md5` tinytext NOT NULL,
|
||||
`isBloquee` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`isSignalee` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
|
||||
CREATE TABLE IF NOT EXISTS `images`
|
||||
(
|
||||
`id` int(20) NOT NULL AUTO_INCREMENT,
|
||||
`remote_addr` varchar(45) NOT NULL,
|
||||
`date_action` datetime NOT NULL,
|
||||
`old_name` varchar(255) NOT NULL,
|
||||
`new_name` varchar(30) NOT NULL,
|
||||
`size` int(11) NOT NULL,
|
||||
`height` int(11) NOT NULL,
|
||||
`width` int(11) NOT NULL,
|
||||
`last_view` date NOT NULL,
|
||||
`nb_view_v4` int(11) NOT NULL,
|
||||
`nb_view_v6` int(11) NOT NULL,
|
||||
`md5` varchar(32) NOT NULL,
|
||||
`isBloquee` tinyint(1) NOT NULL,
|
||||
`isSignalee` tinyint(1) NOT NULL,
|
||||
`isApprouvee` tinyint(1) NOT NULL,
|
||||
`abuse_network` varchar(45) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `statutImage` (`isBloquee`, `isApprouvee`, `isSignalee`) USING BTREE,
|
||||
KEY `abuse_network_bloquee` (`abuse_network`,`isBloquee`) USING BTREE,
|
||||
KEY `abuse_network_approuvee` (`abuse_network`,`isApprouvee`),
|
||||
KEY `isApprouvee` (`isApprouvee`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Structure de la table `login`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `login` (
|
||||
`pk_login` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`ip_login` text NOT NULL,
|
||||
`date_login` datetime NOT NULL,
|
||||
`pk_membres` int(11) NOT NULL,
|
||||
PRIMARY KEY (`pk_login`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
|
||||
CREATE TABLE IF NOT EXISTS `login`
|
||||
(
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`remote_addr` varchar(45) NOT NULL,
|
||||
`date_action` datetime NOT NULL,
|
||||
`membres_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `membres_id` (`membres_id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Structure de la table `membres`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `membres` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`email` text NOT NULL,
|
||||
`login` text NOT NULL,
|
||||
`password` text NOT NULL,
|
||||
`date_inscription` date NOT NULL,
|
||||
`ip_inscription` text NOT NULL,
|
||||
`lvl` tinyint(4) NOT NULL,
|
||||
`isActif` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`token` text,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
|
||||
CREATE TABLE IF NOT EXISTS `membres`
|
||||
(
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`email` text NOT NULL,
|
||||
`login` text NOT NULL,
|
||||
`password` text NOT NULL,
|
||||
`date_action` date NOT NULL,
|
||||
`remote_addr` varchar(45) NOT NULL,
|
||||
`lvl` tinyint(1) NOT NULL,
|
||||
`isActif` tinyint(1) NOT NULL,
|
||||
`token` text NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Structure de la table `possede`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `possede` (
|
||||
`image_id` int(11) NOT NULL,
|
||||
`pk_membres` int(11) NOT NULL,
|
||||
PRIMARY KEY (`image_id`,`pk_membres`),
|
||||
KEY `image_id` (`image_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
CREATE TABLE IF NOT EXISTS `possede`
|
||||
(
|
||||
`images_id` int(11) NOT NULL,
|
||||
`membres_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`images_id`, `membres_id`),
|
||||
KEY `membres_id` (`membres_id`)
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Structure de la table `thumbnails`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `thumbnails` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`id_image` int(11) NOT NULL,
|
||||
`date_creation` date NULL DEFAULT NULL,
|
||||
`new_name` text NOT NULL,
|
||||
`size` int(11) NOT NULL,
|
||||
`height` int(11) NOT NULL,
|
||||
`width` int(11) NOT NULL,
|
||||
`last_view` date NULL DEFAULT NULL,
|
||||
`nb_view_v4` int(11) NOT NULL DEFAULT '0',
|
||||
`nb_view_v6` int(11) NOT NULL DEFAULT '0',
|
||||
`md5` tinytext NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `id_image` (`id_image`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
CREATE TABLE IF NOT EXISTS `thumbnails`
|
||||
(
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`images_id` int(11) NOT NULL,
|
||||
`is_preview` tinyint(1) NOT NULL,
|
||||
`date_action` date NOT NULL,
|
||||
`new_name` varchar(30) NOT NULL,
|
||||
`size` int(11) NOT NULL,
|
||||
`height` int(11) NOT NULL,
|
||||
`width` int(11) NOT NULL,
|
||||
`last_view` date NOT NULL,
|
||||
`nb_view_v4` int(11) NOT NULL,
|
||||
`nb_view_v6` int(11) NOT NULL,
|
||||
`md5` varchar(32) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `images_id` (`images_id`) USING BTREE
|
||||
) ENGINE = MyISAM
|
||||
DEFAULT CHARSET = utf8;
|
||||
|
||||
--
|
||||
-- Création du compte administrateur
|
||||
--
|
||||
INSERT INTO `membres` (`id`, `email`, `login`, `password`, `date_inscription`, `ip_inscription`, `lvl`) VALUES
|
||||
(1, 'john.doe@example.com', 'admin', '$2y$10$2mn2aXq7R2ROZhi9R3H1iO95vSXo0Vd02u3vAdAZSkZhcBq4Vd1bu', DATE(NOW()), '127.0.0.1', 2);
|
||||
INSERT INTO `membres` (`id`, `email`, `login`, `password`, `date_action`, `remote_addr`, `lvl`, `isActif`,
|
||||
`token`)
|
||||
VALUES (1, 'john.doe@example.com', 'admin', '$2y$10$2mn2aXq7R2ROZhi9R3H1iO95vSXo0Vd02u3vAdAZSkZhcBq4Vd1bu', DATE(NOW()),
|
||||
'127.0.0.1', 2, 1, '');
|
||||
|
||||
--
|
||||
-- Images 404 & bannie
|
||||
--
|
||||
INSERT INTO `images` (`id`, `ip_envoi`, `date_envoi`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`, `nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`) VALUES
|
||||
(1, '127.0.0.1', '2008-01-01 00:00:00', '_image_404.png', '_image_404.png', 30703, 150, 640, NULL, 0, 0, '6858ce6ddc171a0fd9640831a5e74dfd', 0, 0),
|
||||
(2, '127.0.0.1', '2008-01-01 00:00:00', '_image_banned.png', '_image_banned.png', 28713, 150, 640, NULL, 0, 0, '12c357976276091e7cd42e98debb7fb1', 0, 0);
|
||||
INSERT INTO `images` (`id`, `remote_addr`, `date_action`, `old_name`, `new_name`, `size`, `height`, `width`, `last_view`,
|
||||
`nb_view_v4`, `nb_view_v6`, `md5`, `isBloquee`, `isSignalee`, `isApprouvee`, `abuse_network`)
|
||||
VALUES (1, '127.0.0.1', '2008-01-01 00:00:00', '_image_404.png', '_image_404.png', 30703, 150, 640, '0000-00-00', 0, 0,
|
||||
'6858ce6ddc171a0fd9640831a5e74dfd', 0, 0, 1, '127.0.0'),
|
||||
(2, '127.0.0.1', '2008-01-01 00:00:00', '_image_banned.png', '_image_banned.png', 28713, 150, 640, '0000-00-00',
|
||||
0, 0, '12c357976276091e7cd42e98debb7fb1', 0, 0, 1, '127.0.0');
|
||||
|
||||
--
|
||||
-- Assignation à l'administrateur
|
||||
--
|
||||
INSERT INTO `possede` (`image_id`, `pk_membres`) VALUES ('1', '1'), ('2', '1');
|
||||
INSERT INTO `possede` (`images_id`, `membres_id`)
|
||||
VALUES ('1', '1'),
|
||||
('2', '1');
|
42
delete.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,7 +24,6 @@ namespace ImageHeberg;
|
|||
if (!defined('_PHPUNIT_')) {
|
||||
require 'config/config.php';
|
||||
}
|
||||
require _TPL_TOP_;
|
||||
|
||||
$erreur = false;
|
||||
$msgErreur = '';
|
||||
|
@ -32,7 +31,7 @@ $msgErreur = '';
|
|||
/**
|
||||
* Vérification du paramètre
|
||||
*/
|
||||
if (!isset($_GET['id']) || !isset($_GET['type'])) {
|
||||
if (!isset($_GET['id'], $_GET['type'])) {
|
||||
$erreur = true;
|
||||
$msgErreur .= 'La page n\'a pas été appelée correctement !<br />';
|
||||
}
|
||||
|
@ -41,7 +40,7 @@ if (!isset($_GET['id']) || !isset($_GET['type'])) {
|
|||
* Chargement de l'image depuis la BDD
|
||||
*/
|
||||
if (!$erreur) {
|
||||
if ((int) $_GET['type'] === RessourceObject::TYPE_IMAGE) {
|
||||
if ((int)$_GET['type'] === RessourceObject::TYPE_IMAGE) {
|
||||
$monImage = new ImageObject();
|
||||
} else {
|
||||
$monImage = new MiniatureObject();
|
||||
|
@ -62,7 +61,13 @@ if (!$erreur) {
|
|||
* -> Envoi il y a moins d'une heure par la même @ IP
|
||||
*/
|
||||
if (!$erreur) {
|
||||
if ($monImage->isProprietaire() || ((strtotime($monImage->getDateEnvoiBrute()) + 3600) > strtotime("now") && $monImage->getIpEnvoi() === $_SERVER['REMOTE_ADDR'])) {
|
||||
if (
|
||||
$monImage->isProprietaire()
|
||||
|| (
|
||||
(strtotime($monImage->getDateEnvoiBrute()) + 3600) > time()
|
||||
&& $monImage->getIpEnvoi() === $_SERVER['REMOTE_ADDR']
|
||||
)
|
||||
) {
|
||||
// Effacement...
|
||||
$monImage->supprimer();
|
||||
} else {
|
||||
|
@ -70,22 +75,21 @@ if (!$erreur) {
|
|||
$msgErreur = 'Vous n\'avez pas le droit de supprimer cette image !<br />';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<h1 class="mb-3"><small>Suppression du fichier</small></h1>
|
||||
<?php if (!empty($msgErreur)) : ?>
|
||||
|
||||
// Pas d'erreur => Redirection sur la page d'accueil
|
||||
if (empty($erreur)) {
|
||||
header('Location: ' . _URL_HTTPS_ . '?delete_success');
|
||||
} else {
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Suppression du fichier</small></h1>
|
||||
<div class="alert alert-danger">
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
|
||||
<b>Une erreur a été rencontrée !</b>
|
||||
<br />
|
||||
<?= $msgErreur ?>
|
||||
<br/>
|
||||
<?= $msgErreur ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="alert alert-success">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
|
||||
<b>L'image a été supprimée avec succès !</b>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php require _TPL_BOTTOM_; ?>
|
||||
<?php
|
||||
require _TPL_BOTTOM_;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,18 +24,32 @@ namespace ImageHeberg;
|
|||
/*
|
||||
* Affichage d'une image & mise à jour des stats
|
||||
*/
|
||||
require 'config/config.php';
|
||||
if (!defined('_PHPUNIT_')) {
|
||||
require 'config/config.php';
|
||||
}
|
||||
|
||||
// URL demandée
|
||||
$url = $_SERVER['REQUEST_URI'];
|
||||
// Nom du fichier demandé
|
||||
$fileName = basename($url);
|
||||
// Nom du fichier demandé - Nettoyer les paramètres
|
||||
$fileName = basename(parse_url($url, PHP_URL_PATH));
|
||||
|
||||
// Faut-il forcer l'affichage (et ne pas enregistrer les stats) ?
|
||||
$adminForceAffichage = false;
|
||||
|
||||
/**
|
||||
* Gestion du God mode
|
||||
*/
|
||||
if (
|
||||
str_contains($url, 'forceDisplay=1') // Mis en premier pour éviter d'ouvrir des sessions inutiles
|
||||
&& UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN, false)
|
||||
) {
|
||||
$adminForceAffichage = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Définition du type
|
||||
*/
|
||||
$monObjet;
|
||||
if (preg_match("#/" . _REPERTOIRE_MINIATURE_ . "#", trim($url))) {
|
||||
if (preg_match('#/' . _REPERTOIRE_MINIATURE_ . '#', trim($url))) {
|
||||
// Miniature
|
||||
$monObjet = new MiniatureObject();
|
||||
} else {
|
||||
|
@ -44,35 +58,62 @@ if (preg_match("#/" . _REPERTOIRE_MINIATURE_ . "#", trim($url))) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Est-ce que le fichier existe ?
|
||||
* Est-ce que le fichier existe en BDD et sur le système de fichier ?
|
||||
*/
|
||||
if (!$monObjet->charger($fileName)) {
|
||||
if (
|
||||
!$monObjet->charger($fileName)
|
||||
|| !file_exists($monObjet->getPathMd5())
|
||||
) {
|
||||
// Fichier non trouvé...
|
||||
$monObjet = new ImageObject();
|
||||
$monObjet->charger(_IMAGE_404_);
|
||||
// Envoi d'un header en 404
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
header('HTTP/2 404 Not Found');
|
||||
} elseif (
|
||||
isset($_SERVER['HTTP_USER_AGENT'])
|
||||
&& in_array($_SERVER['HTTP_USER_AGENT'], _ABUSE_DISABLE_PICS_WHEN_USERE_AGENT_, true)
|
||||
) {
|
||||
// Détection des User-Agent malveillant et blocage des images demandées
|
||||
$monObjet->setSignalee(true);
|
||||
$monObjet->sauver();
|
||||
|
||||
if (!_PHPUNIT_) {
|
||||
// Générer un mail d'erreur à l'admin
|
||||
require 'cron/abuse.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Le fichier est-il bloqué ?
|
||||
*/
|
||||
if ($monObjet->isBloquee() || $monObjet->isSignalee()) {
|
||||
if (
|
||||
!$adminForceAffichage
|
||||
&& ($monObjet->isBloquee() || $monObjet->isSignalee())
|
||||
) {
|
||||
$monObjet = new ImageObject();
|
||||
$monObjet->charger(_IMAGE_BAN_);
|
||||
// Envoi d'un header en 451 -> Unavailable For Legal Reasons
|
||||
header('HTTP/2 451 Unavailable For Legal Reasons');
|
||||
} elseif (
|
||||
!$adminForceAffichage
|
||||
&& !$monObjet->isApprouvee()
|
||||
&& (
|
||||
// Image non suspecte
|
||||
(!$monObjet->isSuspecte() && $monObjet->getNbViewPerDay() > _ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_)
|
||||
// Image suspecte -> seuils réduits
|
||||
|| ($monObjet->isSuspecte() && $monObjet->getNbViewPerDay() > (_ABUSE_NB_AFFICHAGES_PAR_JOUR_BLOCAGE_AUTO_ / _ABUSE_DIVISION_SEUILS_SI_SUSPECT_))
|
||||
)
|
||||
) {
|
||||
// Lancer un blocage de l'image si trop affichée
|
||||
require 'cron/abuse.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Mise à jour des stats d'affichage
|
||||
*/
|
||||
if (filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
// IPv4
|
||||
$monObjet->setNbViewIpv4PlusUn();
|
||||
} else {
|
||||
// IPv6
|
||||
$monObjet->setNbViewIpv6PlusUn();
|
||||
if (!$adminForceAffichage) {
|
||||
$monObjet->updateStatsAffichage($_SERVER['REMOTE_ADDR']);
|
||||
}
|
||||
$monObjet->sauver();
|
||||
|
||||
/**
|
||||
* Fermeture du lien sur la BDD
|
||||
|
@ -83,7 +124,7 @@ MaBDD::close();
|
|||
* Envoi du bon entête HTTP
|
||||
*/
|
||||
if (!_PHPUNIT_) {
|
||||
header("Content-type: " . Outils::getMimeType($monObjet->getPathMd5()));
|
||||
header('Content-type: ' . HelperImage::getMimeType($monObjet->getPathMd5()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
0
files/z_cache/_dummy
Normal file
180
index.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -22,14 +22,26 @@
|
|||
namespace ImageHeberg;
|
||||
|
||||
require 'config/config.php';
|
||||
require _TPL_TOP_;
|
||||
|
||||
// Anti-flood
|
||||
$maSession = new SessionObject();
|
||||
$maSession->setFlag();
|
||||
|
||||
// Désactiver l'envoi d'images
|
||||
$uploadDisabled = false;
|
||||
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Envoyer une image</small></h1>
|
||||
<?php if (MetaObject::getHDDUsage() > _QUOTA_MAXIMAL_IMAGES_GO_) : ?>
|
||||
<h1 class="mb-3"><small>Envoyer une image</small></h1>
|
||||
<?php if (isset($_GET['delete_success'])) : ?>
|
||||
<div class="alert alert-success">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
|
||||
<b>L'image a été supprimée avec succès !</b>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (HelperSysteme::getHDDUsage() > _QUOTA_MAXIMAL_IMAGES_GO_) : ?>
|
||||
<?php $uploadDisabled = true; ?>
|
||||
<div class="alert alert-danger">
|
||||
<?= _SITE_NAME_ ?> est victime de son succès : trop d'images ont été envoyées
|
||||
et tout l'espace disque acheté est utilisé !
|
||||
|
@ -37,76 +49,92 @@ $maSession->setFlag();
|
|||
Si vous souhaitez soutenir le projet, merci d'utiliser <a href="contact.php">le formulaire de contact</a>.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="alert alert-info">
|
||||
<?= _SITE_NAME_ ?> est un service gratuit vous permettant d'héberger vos images sur internet.
|
||||
<ul>
|
||||
<li>
|
||||
Image de type JPG, PNG, GIF
|
||||
</li>
|
||||
<li>
|
||||
Taille maximale : <?= round(_IMAGE_POIDS_MAX_ / 1048576, 1) ?> Mo
|
||||
</li>
|
||||
<li>
|
||||
Dimensions maximales : <?= _IMAGE_DIMENSION_MAX_ ?> x <?= _IMAGE_DIMENSION_MAX_ ?> pixels
|
||||
(hauteur x largeur)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form enctype="multipart/form-data" action="<?= _URL_HTTPS_ ?>upload.php" method="post" class="mb-3">
|
||||
<div class="mb-3">
|
||||
<label for="fichier" class="col-mb-3 form-label">Fichier à envoyer</label>
|
||||
<div class="col-md-9">
|
||||
<input type="file" accept="image/*" name="fichier" id="fichier" required="required" <?= (MetaObject::getHDDUsage() > _QUOTA_MAXIMAL_IMAGES_GO_) ? 'disabled="disabled"' : '' ?> class="form-control">
|
||||
</div>
|
||||
<div class="help-block">
|
||||
Tout envoi de fichier implique l'acceptation des
|
||||
<a href="cgu.php">Conditions Générales d'Utilisation</a> du service.
|
||||
</div>
|
||||
</div>
|
||||
<h3>Options</h3>
|
||||
<span class="help-block"><em>Le ratio de l'image sera conservé.</em></span>
|
||||
<div class="mb-3">
|
||||
<label class="col-mb-3 form-label">Rotation de l'image</label>
|
||||
<div class="col-md-9">
|
||||
<select name="angleRotation" class="form-select">
|
||||
<option value="" selected>-- Ne pas effectuer --</option>
|
||||
<optgroup label="Rotation vers la gauche">
|
||||
<option value="90">90° (¼ tour)</option>
|
||||
<option value="180">180° (½ tour)</option>
|
||||
<option value="270">270° (¾ tour)</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="col-mb-3 form-label">Faire une miniature</label>
|
||||
<div class="col-md-9">
|
||||
<select name="dimMiniature" class="form-select">
|
||||
<option value="" selected>-- Ne pas effectuer --</option>
|
||||
<option value="100x100">Avatar (100x100)</option>
|
||||
<option value="320x240">Miniature (320x240)</option>
|
||||
<option value="640x480">Miniature XL (640x480)</option>
|
||||
<option value="700x700">Miniature Forum (700x700)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="col-mb-3 form-label">Redimensionner l'image</label>
|
||||
<div class="col-md-9">
|
||||
<select name="redimImage" class="form-select">
|
||||
<option value="" selected>-- Ne pas effectuer --</option>
|
||||
<option value="320x240">320x240</option>
|
||||
<option value="640x480">640x480</option>
|
||||
<option value="800x600">800x600</option>
|
||||
<option value="1024x768">1024x768</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-success" name="Submit" type="submit"><span class="fas fa-cloud-upload-alt"></span> Envoyer</button>
|
||||
</form>
|
||||
<?php if (_TOR_DISABLE_UPLOAD_ && Tor::checkIp($_SERVER['REMOTE_ADDR'])) : ?>
|
||||
<?php $uploadDisabled = true; ?>
|
||||
<div class="alert alert-danger">
|
||||
Suite à un abus d'utilisation de <?= _SITE_NAME_ ?>, l'envoi d'image est impossible depuis le réseau Tor.
|
||||
<br>
|
||||
Si vous le souhaitez contacter l'administrateur du site, merci d'utiliser <a href="contact.php">le formulaire de contact</a>.
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
||||
<?php endif; ?>
|
||||
<?php if (_ABUSE_DISABLE_UPLOAD_AFTER_X_IMAGES_ > 0 && HelperAbuse::checkIpReputation($_SERVER['REMOTE_ADDR']) >= _ABUSE_DISABLE_UPLOAD_AFTER_X_IMAGES_) : ?>
|
||||
<?php $uploadDisabled = true; ?>
|
||||
<div class="alert alert-danger">
|
||||
Suite à un abus d'utilisation de <?= _SITE_NAME_ ?> depuis votre plage adresse IP (<?= $_SERVER['REMOTE_ADDR'] ?>), l'envoi d'image ne vous est plus accessible.
|
||||
<br>
|
||||
Si vous le souhaitez contacter l'administrateur du site, merci d'utiliser <a href="contact.php">le formulaire de contact</a>.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="alert alert-info">
|
||||
<?= _SITE_NAME_ ?> est un service gratuit vous permettant d'héberger vos images sur internet.
|
||||
<ul>
|
||||
<li>
|
||||
Image de type <?= strtoupper(implode(', ', _ACCEPTED_EXTENSIONS_)) ?>
|
||||
</li>
|
||||
<li>
|
||||
Taille maximale : <?= round(_IMAGE_POIDS_MAX_ / 1048576, 1) ?> Mo
|
||||
</li>
|
||||
<li>
|
||||
Dimensions maximales : <?= _IMAGE_DIMENSION_MAX_ ?> x <?= _IMAGE_DIMENSION_MAX_ ?> pixels
|
||||
(hauteur x largeur)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form enctype="multipart/form-data" action="<?= _URL_HTTPS_ ?>upload.php" method="post" class="mb-3">
|
||||
<div class="mb-3">
|
||||
<label for="fichier" class="col-mb-3 form-label">Fichier à envoyer</label>
|
||||
<div class="col-md-9">
|
||||
<input type="file" accept="image/*" name="fichier" id="fichier" required="required" <?= ($uploadDisabled ? 'disabled="disabled"' : '') ?> class="form-control">
|
||||
</div>
|
||||
<div class="help-block">
|
||||
Tout envoi de fichier implique l'acceptation des
|
||||
<a href="cgu.php">Conditions Générales d'Utilisation</a> du service.
|
||||
</div>
|
||||
</div>
|
||||
<h3>Options</h3>
|
||||
<span class="help-block"><em>Le ratio de l'image sera conservé.</em></span>
|
||||
<div class="mb-3">
|
||||
<label for="angleRotation" class="col-mb-3 form-label">Rotation de l'image</label>
|
||||
<div class="col-md-9">
|
||||
<select name="angleRotation" id="angleRotation" class="form-select">
|
||||
<option value="" selected>-- Ne pas effectuer --</option>
|
||||
<optgroup label="Rotation vers la droite (sens horaire)">
|
||||
<option value="90">90° (¼ tour)</option>
|
||||
<option value="180">180° (½ tour)</option>
|
||||
<option value="270">270° (¾ tour)</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="dimMiniature" class="col-mb-3 form-label">Faire une miniature</label>
|
||||
<div class="col-md-9">
|
||||
<select name="dimMiniature" id="dimMiniature" class="form-select">
|
||||
<option value="" selected>-- Ne pas effectuer --</option>
|
||||
<option value="100x100">Avatar (100x100)</option>
|
||||
<option value="320x240">Miniature (320x240)</option>
|
||||
<option value="640x480">Miniature XL (640x480)</option>
|
||||
<option value="700x700">Miniature Forum (700x700)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="redimImage" class="col-mb-3 form-label">Redimensionner l'image</label>
|
||||
<div class="col-md-9">
|
||||
<select name="redimImage" id="redimImage" class="form-select">
|
||||
<option value="" selected>-- Ne pas effectuer --</option>
|
||||
<option value="320x240">320x240</option>
|
||||
<option value="640x480">640x480</option>
|
||||
<option value="800x600">800x600</option>
|
||||
<option value="1024x768">1024x768</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-success" name="Submit" type="submit" <?= ($uploadDisabled ? 'disabled="disabled"' : '') ?>><span class="bi-cloud-arrow-up-fill"></span> Envoyer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
52
install.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -25,14 +25,15 @@ namespace ImageHeberg;
|
|||
* Vérification des prérequis basiques
|
||||
* Ce fichier peut être supprimé après l'installation
|
||||
*/
|
||||
echo 'PHP v' . PHP_VERSION . '<br />';
|
||||
|
||||
/* 1 - Existence du fichier de config */
|
||||
$conf = file_exists(__DIR__ . "/config/config.php");
|
||||
$conf = file_exists(__DIR__ . '/config/config.php');
|
||||
if (!$conf) {
|
||||
$msg = "Le fichier de configuration n'existe pas dans config/config.php !";
|
||||
$msg = 'Le fichier de configuration n\'existe pas dans config/config.php !';
|
||||
echo $msg;
|
||||
if (!_PHPUNIT_) {
|
||||
die($msg);
|
||||
} else {
|
||||
echo $msg;
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,44 +41,47 @@ if (!$conf) {
|
|||
if (!defined('_PHPUNIT_')) {
|
||||
require 'config/config.php';
|
||||
}
|
||||
$res = MaBDD::getInstance()->query("SELECT COUNT(*) AS nbImages FROM images");
|
||||
$res = MaBDD::getInstance()->query('SELECT COUNT(*) AS nbImages FROM images');
|
||||
if (!$res) {
|
||||
$msg = "Erreur de connexion à la base de données, vérifiez les identifiants dans le fichier config/config.php !";
|
||||
$msg = 'Erreur de connexion à la base de données, vérifiez les identifiants dans le fichier config/config.php !';
|
||||
echo $msg;
|
||||
if (!_PHPUNIT_) {
|
||||
die($msg);
|
||||
} else {
|
||||
echo $msg;
|
||||
die();
|
||||
}
|
||||
}
|
||||
$resultat = $res->fetch()->nbImages;
|
||||
if ($resultat < 2) { // 404 & banned par défaut
|
||||
$msg = "La base de données n'a pas été initialisée correctement avec le fichier database.sql !";
|
||||
$msg = 'La base de données n\'a pas été initialisée correctement avec le fichier database.sql !';
|
||||
echo $msg;
|
||||
if (!_PHPUNIT_) {
|
||||
die($msg);
|
||||
} else {
|
||||
echo $msg;
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
/* 3 - droits sur répertoire des images */
|
||||
if (!is_writable(_PATH_IMAGES_ . '_image_404.png')) {
|
||||
$msg = "PHP doit pouvoir écrire dans les répertoires " . _REPERTOIRE_IMAGE_ . "* !";
|
||||
$msg = 'PHP doit pouvoir écrire dans les répertoires ' . _REPERTOIRE_IMAGE_ . '* !';
|
||||
echo $msg;
|
||||
if (!_PHPUNIT_) {
|
||||
die($msg);
|
||||
} else {
|
||||
echo $msg;
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
/* 4 - gestion des sessions */
|
||||
if (headers_sent()) {
|
||||
$msg = "Les entêtes (sessions) ont déjà été envoyés, corrigez votre configuration serveur !";
|
||||
$msg = 'Les entêtes (sessions) ont déjà été envoyés, corrigez votre configuration serveur !';
|
||||
if (!_PHPUNIT_) {
|
||||
die($msg);
|
||||
} else {
|
||||
// Ne rien faire, nous sommes dans l'environnement de tests qui a déjà affiché des données (phpunit...)
|
||||
//echo $msg;
|
||||
}
|
||||
// Sinon, ne rien faire, nous sommes dans l'environnement de tests qui a déjà affiché des données (phpunit...)
|
||||
}
|
||||
|
||||
echo "L'installation est OK !";
|
||||
/* Configuration */
|
||||
if (_PATH_ !== __DIR__ . '/') {
|
||||
$msg = 'La variable _PATH_ (' . _PATH_ . ') n\'est pas cohérente avec l\'emplacement de l\'application (' . __DIR__ . ')';
|
||||
echo $msg;
|
||||
if (!_PHPUNIT_) {
|
||||
die();
|
||||
}
|
||||
}
|
||||
echo 'L\'installation est OK !';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -33,21 +33,21 @@ if (isset($_POST['valider'])) {
|
|||
$messageErreur = '';
|
||||
|
||||
if (empty($_POST['userName'])) {
|
||||
$messageErreur .= "<br />Merci de saisir un identifiant.";
|
||||
$messageErreur .= '<br />Merci de saisir un identifiant.';
|
||||
}
|
||||
if (empty($_POST['userPassword'])) {
|
||||
$messageErreur .= "<br />Merci de saisir un mot de passe.";
|
||||
$messageErreur .= '<br />Merci de saisir un mot de passe.';
|
||||
}
|
||||
// Si tout est bon
|
||||
if (empty($messageErreur)) {
|
||||
if ($monUtilisateur->connexion($_POST['userName'], $_POST['userPassword']) === true) {
|
||||
if (!_PHPUNIT_) {
|
||||
// Succès -> redirige sur la page d'accueil
|
||||
header('Location: ' . _URL_);
|
||||
header('Location: ' . _URL_HTTPS_);
|
||||
die();
|
||||
}
|
||||
} else {
|
||||
$messageErreur .= "<br />Erreur dans vos identifiants.";
|
||||
$messageErreur .= '<br />Erreur dans vos identifiants.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,19 +61,19 @@ if (isset($messageErreur)) :
|
|||
<?= $messageErreur ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<h1 class="mb-3"><small>Connexion à mon compte</small></h1>
|
||||
<h1 class="mb-3"><small>Connexion à mon compte</small></h1>
|
||||
|
||||
<form method="post">
|
||||
<div class="mb-3 row form-floating">
|
||||
<input type="text" class="form-control" name="userName" id="userName" placeholder="Identifiant" value="<?= $monUtilisateur->getUserName() ?>" required="required">
|
||||
<label for="userName">Identifiant</label>
|
||||
</div>
|
||||
<div class="mb-3 row form-floating">
|
||||
<input type="password" class="form-control" name="userPassword" id="userPassword" placeholder="Mot de passe" required="required">
|
||||
<label for="userPassword">Mot de passe</label>
|
||||
</div>
|
||||
<button type="submit" name="valider" class="btn btn-success"><span class="fas fa-sign-in-alt"></span> Se connecter</button>
|
||||
<a class="btn btn-outline-warning" role="button" disabled>Mot de passe oublié (à venir)</a>
|
||||
<a class="btn btn-info" href="<?= _URL_MEMBRE_ ?>creerCompte.php" role="button"><span class="fas fa-save"></span> S'inscrire</a>
|
||||
</form>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
<form method="post">
|
||||
<div class="mb-3 row form-floating">
|
||||
<input type="text" class="form-control" name="userName" id="userName" placeholder="Identifiant" value="<?= $monUtilisateur->getUserName() ?>" required="required">
|
||||
<label for="userName">Identifiant</label>
|
||||
</div>
|
||||
<div class="mb-3 row form-floating">
|
||||
<input type="password" class="form-control" name="userPassword" id="userPassword" placeholder="Mot de passe" required="required">
|
||||
<label for="userPassword">Mot de passe</label>
|
||||
</div>
|
||||
<button type="submit" name="valider" class="btn btn-success"><span class="bi-box-arrow-in-right"></span> Se connecter</button>
|
||||
<a class="btn btn-outline-warning" role="button" disabled>Mot de passe oublié (à venir)</a>
|
||||
<a class="btn btn-info" href="<?= _URL_MEMBRE_ ?>creerCompte.php" role="button"><span class="bi-person-add"></span> S'inscrire</a>
|
||||
</form>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -24,7 +24,6 @@ namespace ImageHeberg;
|
|||
if (!defined('_PHPUNIT_')) {
|
||||
require '../config/config.php';
|
||||
}
|
||||
require _TPL_TOP_;
|
||||
|
||||
// Anti flood
|
||||
$maSession = new SessionObject();
|
||||
|
@ -40,25 +39,30 @@ if (isset($_POST['valider']) && $maSession->checkFlag()) {
|
|||
|
||||
if (empty($_POST['userName'])) {
|
||||
$flagCreation = false;
|
||||
$messageErreur .= "<br />Merci de saisir un identifiant.";
|
||||
$messageErreur .= '<br />Merci de saisir un identifiant.';
|
||||
}
|
||||
if (empty($_POST['userPassword'])) {
|
||||
$flagCreation = false;
|
||||
$messageErreur .= "<br />Merci de saisir un mot de passe.";
|
||||
$messageErreur .= '<br />Merci de saisir un mot de passe.';
|
||||
}
|
||||
if (empty($_POST['userMail'])) {
|
||||
$flagCreation = false;
|
||||
$messageErreur .= "<br />Merci de saisir une adresse courriel.";
|
||||
$messageErreur .= '<br />Merci de saisir une adresse courriel.';
|
||||
}
|
||||
// Vérification du bon format de l'adresse mail
|
||||
if (filter_var($_POST['userMail'], FILTER_VALIDATE_EMAIL) === false) {
|
||||
$flagCreation = false;
|
||||
$messageErreur .= "<br />L'adresse courriel saisie n'est pas correcte.";
|
||||
$messageErreur .= '<br />L\'adresse courriel saisie n\'est pas correcte.';
|
||||
}
|
||||
// Disponibilité de l'email
|
||||
if (UtilisateurObject::verifierEmailDisponible($_POST['userMail']) !== true) {
|
||||
$flagCreation = false;
|
||||
$messageErreur .= '<br />Cet email n\'est pas disponible. Merci d\'en choisir un autre.';
|
||||
}
|
||||
// Disponibilité du login
|
||||
if (UtilisateurObject::verifierLoginDisponible($_POST['userName']) !== true) {
|
||||
$flagCreation = false;
|
||||
$messageErreur .= "<br />Ce nom d'utilisateur n'est pas possible. Merci d'en choisir un autre.";
|
||||
$messageErreur .= '<br />Ce nom d\'utilisateur n\'est pas possible. Merci d\'en choisir un autre.';
|
||||
}
|
||||
|
||||
// Données administratives : droits de l'utilisateur
|
||||
|
@ -69,7 +73,7 @@ if (isset($_POST['valider']) && $maSession->checkFlag()) {
|
|||
// Mot de passe - Crypté
|
||||
$monUtilisateur->setPasswordToCrypt($_POST['userPassword']);
|
||||
// Adresse mail
|
||||
$monUtilisateur->setEmail($_POST['userMail']);
|
||||
$monUtilisateur->setEmail(strtolower($_POST['userMail']));
|
||||
|
||||
// Si tout est bon
|
||||
if ($flagCreation) {
|
||||
|
@ -84,33 +88,37 @@ if (isset($_POST['valider']) && $maSession->checkFlag()) {
|
|||
|
||||
if (!_PHPUNIT_) {
|
||||
// Redirection sur la page d'accueil - sauf si mode tests
|
||||
header('Location: ' . _URL_);
|
||||
header('Location: ' . _URL_HTTPS_);
|
||||
die();
|
||||
}
|
||||
} else {
|
||||
echo '<div class="alert alert-danger"><strong>La création de votre compte n\'est pas possible :</strong>';
|
||||
echo $messageErreur;
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
require _TPL_TOP_;
|
||||
$maSession->setFlag();
|
||||
?>
|
||||
<h1 class="mb-3"><small>Créer mon compte</small></h1>
|
||||
|
||||
<form method="post">
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="text" class="form-control" name="userName" id="userName" value="<?= $monUtilisateur->getUserName() ?>" required="required">
|
||||
<label for="userName">Identifiant</label>
|
||||
<h1 class="mb-3"><small>Créer mon compte</small></h1>
|
||||
<?php if (!empty($messageErreur)) : ?>
|
||||
<div class="alert alert-danger"><strong>La création de votre compte n'est pas possible :</strong>
|
||||
<?= $messageErreur ?>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="password" class="form-control" name="userPassword" id="userPassword" required="required">
|
||||
<label for="userPassword">Mot de passe</label>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="email" class="form-control" name="userMail" id="userMail" value="<?= $monUtilisateur->getEmail() ?>" required="required">
|
||||
<label for="userMail">Adresse courriel</label>
|
||||
<div class="form-text">Utilisée uniquement en cas de réinitialisation de votre mot de passe.</div>
|
||||
</div>
|
||||
<button type="submit" name="valider" class="btn btn-success">M'inscrire</button>
|
||||
</form>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
<?php endif; ?>
|
||||
<form method="post">
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="text" class="form-control" name="userName" id="userName" value="<?= $monUtilisateur->getUserName() ?>" required="required">
|
||||
<label for="userName">Identifiant</label>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="password" class="form-control" name="userPassword" id="userPassword" required="required">
|
||||
<label for="userPassword">Mot de passe</label>
|
||||
</div>
|
||||
<div class="mb-3 form-floating">
|
||||
<input type="email" class="form-control" name="userMail" id="userMail" value="<?= $monUtilisateur->getEmail() ?>" required="required">
|
||||
<label for="userMail">Adresse courriel</label>
|
||||
<div class="form-text">Utilisée uniquement en cas de réinitialisation de votre mot de passe.</div>
|
||||
</div>
|
||||
<button type="submit" name="valider" class="btn btn-success">
|
||||
<span class="bi-person-add"></span>
|
||||
M'inscrire
|
||||
</button>
|
||||
</form>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -19,57 +19,80 @@
|
|||
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
// TODO : affichage des images dans la page en javascript ?
|
||||
// TODO : navigation entre les images
|
||||
|
||||
namespace ImageHeberg;
|
||||
|
||||
require __DIR__ . '/../config/config.php';
|
||||
// Vérification des droits d'accès
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_USER);
|
||||
require _TPL_TOP_;
|
||||
// Je récupère la session de mon utilisateur
|
||||
$maSession = new SessionObject();
|
||||
// Et je reprend ses données
|
||||
$monUtilisateur = new UtilisateurObject($maSession->getId());
|
||||
?>
|
||||
<h1 class="mb-3"><small>Mes images</small></h1>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="text-center">
|
||||
<th>Nom de l'image</th>
|
||||
<th>Date d'envoi</th>
|
||||
<th>Dernier affichage</th>
|
||||
<th>Nb. vues</th>
|
||||
<th>Voir</th>
|
||||
<th>Supprimer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
$mesImages = $monUtilisateur->getImages();
|
||||
foreach ((array) $mesImages as $newName) :
|
||||
$uneImage = new ImageObject($newName);
|
||||
require _TPL_TOP_;
|
||||
?>
|
||||
<h1 class="mb-3"><small>Mes images</small></h1>
|
||||
<div class="row">
|
||||
<?php
|
||||
// Charger les objets concernés
|
||||
$mesImages = ImageObject::chargerMultiple($monUtilisateur->getImages(), RessourceObject::SEARCH_BY_NAME);
|
||||
foreach ($mesImages as $uneImage) :
|
||||
$miniature = $uneImage->getMiniatures(true);
|
||||
if ($miniature->count() === 0) {
|
||||
// Duplication de l'image source
|
||||
$tmpFile = tempnam(sys_get_temp_dir(), uniqid('', true));
|
||||
copy($uneImage->getPathMd5(), $tmpFile);
|
||||
|
||||
// Génération de la miniature pour l'aperçu
|
||||
$maMiniature = new MiniatureObject();
|
||||
$maMiniature->setPathTemp($tmpFile);
|
||||
$maMiniature->setIdImage($uneImage->getId());
|
||||
$maMiniature->redimensionner($maMiniature->getPathTemp(), $maMiniature->getPathTemp(), _SIZE_PREVIEW_, _SIZE_PREVIEW_);
|
||||
$maMiniature->setNomTemp('preview_' . $uneImage->getId());
|
||||
$maMiniature->creer();
|
||||
$maMiniature->setIsPreview(true);
|
||||
$maMiniature->sauver();
|
||||
} else {
|
||||
$maMiniature = new MiniatureObject($miniature->offsetGet(0));
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td><?= $uneImage->getNomOriginalFormate() ?></td>
|
||||
<td class="text-center"><?= $uneImage->getDateEnvoiFormatee() ?></td>
|
||||
<td class="text-center"><?= $uneImage->getLastViewFormate() ?></td>
|
||||
<td class="text-center"><?= $uneImage->getNbViewTotal() ?></td>
|
||||
<td class="text-center">
|
||||
<a href='<?= _URL_IMAGES_ ?><?= $uneImage->getNomNouveau() ?>' target="_blank">
|
||||
<span class="fas fa-share-square"></span>
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href='<?= _URL_ ?>delete.php?id=<?= $uneImage->getNomNouveau() ?>&type=<?= RessourceObject::TYPE_IMAGE ?>'
|
||||
target="_blank">
|
||||
<span class="fas fa-trash"></span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="col p-1" style="min-width: <?= _SIZE_PREVIEW_ ?>px;">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<?= $uneImage->getNomOriginalFormate() ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">
|
||||
Envoyée le <?= $uneImage->getDateEnvoiFormatee() ?>
|
||||
<br/>
|
||||
<?= $uneImage->getNbViewTotal() ?> affichage<?= $uneImage->getNbViewTotal() > 1 ? 's' : '' ?> <span title="Date du dernier affichage" class="fw-light fst-italic">(<?= $uneImage->getLastViewFormate() ?>)</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<a href="<?= _URL_IMAGES_ ?><?= $uneImage->getNomNouveau() ?>" title="<?= $uneImage->getNomOriginalFormate() ?>" target="_blank">
|
||||
<img src="<?= $maMiniature->getURL() ?>" class="card-img-bottom rounded-3" alt="<?= $uneImage->getNomOriginalFormate() ?>" style="<?= ($maMiniature->getLargeur() < 256 ? 'max-height: ' . _SIZE_PREVIEW_ . 'px; width: auto;' : 'height: auto; max-width: ' . _SIZE_PREVIEW_ . 'px;') ?>" loading="lazy">
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer text-muted text-end">
|
||||
<a href="<?= _URL_IMAGES_ ?><?= $uneImage->getNomNouveau() ?>" title="Afficher" target="_blank">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary">
|
||||
<span class="bi-box-arrow-up-right"></span>
|
||||
</button>
|
||||
</a>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#linksModal">
|
||||
<span class="bi-link-45deg"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-warning" data-bs-toggle="modal" data-bs-target="#renameModal">
|
||||
<span class="bi-pencil"></span>
|
||||
</button>
|
||||
<a href="<?= _URL_HTTPS_ ?>delete.php?id=<?= $uneImage->getNomNouveau() ?>&type=<?= RessourceObject::TYPE_IMAGE ?>" title="Effacer" target="_blank">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger">
|
||||
<span class="bi-trash"></span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_; ?>
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -25,13 +25,13 @@ if (!defined('_PHPUNIT_')) {
|
|||
require '../config/config.php';
|
||||
}
|
||||
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_USER);
|
||||
require _TPL_TOP_;
|
||||
|
||||
// Je récupère la session de mon utilisateur
|
||||
$maSession = new SessionObject();
|
||||
// Et je reprend ses données
|
||||
$monUtilisateur = new UtilisateurObject($maSession->getId());
|
||||
|
||||
require _TPL_TOP_;
|
||||
if (isset($_POST['modifierPwd'])) {
|
||||
// Je vérifie qu'on me donne le bon mot de passe
|
||||
if ($monUtilisateur->connexion($maSession->getUserName(), $_POST['oldUserPassword'])) {
|
||||
|
@ -74,11 +74,11 @@ if (isset($_POST['modifierPwd'])) {
|
|||
?>
|
||||
<div class="alert alert-success">
|
||||
Votre compte a été supprimé !
|
||||
<br />
|
||||
<br/>
|
||||
Les images liées à votre compte n'ont pas été supprimées.
|
||||
<br />
|
||||
<br/>
|
||||
Cette action est irrévocable !
|
||||
<br />
|
||||
<br/>
|
||||
Merci d'avoir utilisé <?= _SITE_NAME_ ?>.
|
||||
</div>
|
||||
<?php
|
||||
|
@ -95,106 +95,100 @@ if (isset($_POST['modifierPwd'])) {
|
|||
}
|
||||
}
|
||||
?>
|
||||
<h1 class="mb-3"><small>Mon compte <?= _SITE_NAME_ ?></small></h1>
|
||||
<h1 class="mb-3"><small>Mon compte <?= _SITE_NAME_ ?></small></h1>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $monUtilisateur->getUserName() ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Membre depuis le : <?= $monUtilisateur->getDateInscriptionFormate() ?>
|
||||
<br />
|
||||
Adresse courriel : <?= $monUtilisateur->getEmail() ?>
|
||||
<br />
|
||||
Images possédées : <?= count($monUtilisateur->getImages()) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modification du mot de passe -->
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapsePwd">
|
||||
Changer de mot de passe <span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapsePwd" class="card-collapse collapse">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<?= $monUtilisateur->getUserName() ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="oldUserPassword" class="form-label">Mot de passe actuel</label>
|
||||
<input type="password" class="form-control" name="oldUserPassword" id="oldUserPassword"
|
||||
placeholder="Mot de passe actuel" required="required">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="newUserPassword" class="form-label">Nouveau mot de passe</label>
|
||||
<input type="password" class="form-control" name="newUserPassword" id="newUserPassword"
|
||||
placeholder="Nouveau mot de passe" required="required">
|
||||
</div>
|
||||
<button type="submit" name="modifierPwd" class="btn btn-success">Modifier le mot de passe</button>
|
||||
</form>
|
||||
Membre depuis le : <?= $monUtilisateur->getDateInscriptionFormate() ?>
|
||||
<br/>
|
||||
Adresse courriel : <?= $monUtilisateur->getEmail() ?>
|
||||
<br/>
|
||||
Images possédées : <?= count($monUtilisateur->getImages()) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Changer l'adresse mail -->
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseMail">
|
||||
Changer d'adresse courriel <span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseMail" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="userMail" class="form-label">Nouvelle adresse courriel</label>
|
||||
<input type="email" class="form-control" name="userMail" id="userMail"
|
||||
placeholder="Nouvelle adresse courriel" required="required">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="userPasswordMail" class="form-label">Mot de passe</label>
|
||||
<input type="password" class="form-control" name="userPasswordMail" id="userPasswordMail"
|
||||
placeholder="Mot de passe" required="required">
|
||||
</div>
|
||||
|
||||
<button type="submit" name="modifierMail" class="btn btn-success">Modifier l'adresse courriel</button>
|
||||
</form>
|
||||
<!-- Modification du mot de passe -->
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapsePwd">
|
||||
Changer de mot de passe <span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapsePwd" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="oldUserPassword" class="form-label">Mot de passe actuel</label>
|
||||
<input type="password" class="form-control" name="oldUserPassword" id="oldUserPassword" placeholder="Mot de passe actuel" required="required">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="newUserPassword" class="form-label">Nouveau mot de passe</label>
|
||||
<input type="password" class="form-control" name="newUserPassword" id="newUserPassword" placeholder="Nouveau mot de passe" required="required">
|
||||
</div>
|
||||
<button type="submit" name="modifierPwd" class="btn btn-success">Modifier le mot de passe</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Supprimer le compte -->
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseDelete">
|
||||
Supprimer mon compte <span class="fas fa-caret-down"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseDelete" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<label class="text-danger form-label">
|
||||
<input type="checkbox" value="" name="confirmeDelete">
|
||||
<span class="fas fa-warning-sign"></span>
|
||||
Je confirme souhaiter supprimer mon compte <?= _SITE_NAME_ ?>.
|
||||
<br />
|
||||
<b>
|
||||
Les images rattachées à mon compte ne seront pas supprimées
|
||||
et ne seront plus supprimables avant leur expiration !
|
||||
</b>
|
||||
<br />
|
||||
Cette action est irrévocable !
|
||||
</label>
|
||||
<!-- Changer l'adresse mail -->
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseMail">
|
||||
Changer d'adresse courriel <span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseMail" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="userMail" class="form-label">Nouvelle adresse courriel</label>
|
||||
<input type="email" class="form-control" name="userMail" id="userMail"
|
||||
placeholder="Nouvelle adresse courriel" required="required">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="userPasswordMail" class="form-label">Mot de passe</label>
|
||||
<input type="password" class="form-control" name="userPasswordMail" id="userPasswordMail"
|
||||
placeholder="Mot de passe" required="required">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="userPasswordDelete" class="form-label">Mot de passe</label>
|
||||
<input type="password" class="form-control" name="userPasswordDelete" id="userPasswordDelete"
|
||||
placeholder="Mot de passe" required="required">
|
||||
</div>
|
||||
|
||||
<button type="submit" name="supprimerCompte" class="btn btn-danger">Supprimer mon compte</button>
|
||||
</form>
|
||||
<button type="submit" name="modifierMail" class="btn btn-success">Modifier l'adresse courriel</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
||||
|
||||
<!-- Supprimer le compte -->
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<a data-bs-toggle="collapse" href="#collapseDelete">
|
||||
Supprimer mon compte <span class="bi-caret-down-fill"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="collapseDelete" class="card-collapse collapse">
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<label class="text-danger form-label">
|
||||
<input type="checkbox" value="" name="confirmeDelete">
|
||||
<span class="bi-exclamation-triangle-fill"></span>
|
||||
Je confirme souhaiter supprimer mon compte <?= _SITE_NAME_ ?>.
|
||||
<br/>
|
||||
<b>Les images rattachées à mon compte ne seront pas supprimées et ne seront plus supprimables avant leur expiration !</b>
|
||||
<br/>
|
||||
Cette action est irrévocable !
|
||||
</label>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="userPasswordDelete" class="form-label">Mot de passe</label>
|
||||
<input type="password" class="form-control" name="userPasswordDelete" id="userPasswordDelete" placeholder="Mot de passe" required="required">
|
||||
</div>
|
||||
|
||||
<button type="submit" name="supprimerCompte" class="btn btn-danger">Supprimer mon compte</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php require _TPL_BOTTOM_ ?>
|
36
stats.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2008-2021 Anael MOBILIA
|
||||
* Copyright 2008-2024 Anael MOBILIA
|
||||
*
|
||||
* This file is part of image-heberg.fr.
|
||||
*
|
||||
|
@ -25,35 +25,30 @@ require 'config/config.php';
|
|||
require _TPL_TOP_;
|
||||
|
||||
// Stats Images
|
||||
$reqImage = MaBDD::getInstance()->query("SELECT COUNT(*) AS nb, SUM(nb_view_v4 * size) AS bpv4, SUM(nb_view_v6 * size) AS bpv6, SUM(nb_view_v4 + nb_view_v6) AS nbAff, SUM(size) as totSize FROM images");
|
||||
/* @var $reqImage PDOStatement */
|
||||
$reqImage = MaBDD::getInstance()->query('SELECT COUNT(*) AS nb, SUM(nb_view_v4 * size) AS bpv4, SUM(nb_view_v6 * size) AS bpv6, SUM(nb_view_v4 + nb_view_v6) AS nbAff, SUM(size) as totSize, MAX(id) as nbTot FROM images');
|
||||
// Je récupère les valeurs
|
||||
$valImage = $reqImage->fetch();
|
||||
|
||||
// Stats Miniatures
|
||||
$reqMiniature = MaBDD::getInstance()->query("SELECT COUNT(*) AS nb, SUM(nb_view_v4 * size) AS bpv4, SUM(nb_view_v6 * size) AS bpv6, SUM(nb_view_v4 + nb_view_v6) AS nbAff, SUM(size) as totSize FROM thumbnails");
|
||||
/* @var $reqMiniature PDOStatement */
|
||||
$reqMiniature = MaBDD::getInstance()->query('SELECT COUNT(*) AS nb, SUM(nb_view_v4 * size) AS bpv4, SUM(nb_view_v6 * size) AS bpv6, SUM(nb_view_v4 + nb_view_v6) AS nbAff, SUM(size) as totSize FROM thumbnails');
|
||||
// Je récupère les valeurs
|
||||
$valMiniature = $reqMiniature->fetch();
|
||||
|
||||
// Stats membres
|
||||
$reqMembre = MaBDD::getInstance()->query("SELECT COUNT(*) AS nb FROM membres");
|
||||
/* @var $reqMembre PDOStatement */
|
||||
$reqMembre = MaBDD::getInstance()->query('SELECT COUNT(*) AS nb FROM membres');
|
||||
// Je récupère les valeurs
|
||||
$valMembre = $reqMembre->fetch();
|
||||
|
||||
// Stats membres -> possède
|
||||
$reqPossede = MaBDD::getInstance()->query("SELECT COUNT(*) AS nb FROM possede");
|
||||
/* @var $reqPossede PDOStatement */
|
||||
$reqPossede = MaBDD::getInstance()->query('SELECT COUNT(*) AS nb FROM possede');
|
||||
// Je récupère les valeurs
|
||||
$valPossede = $reqPossede->fetch();
|
||||
|
||||
// Bande passante
|
||||
$bp_v4 = $valImage->bpv4 + $valMiniature->bpv4;
|
||||
$bp_all = 1;
|
||||
$bp_all += $valImage->bpv4 + $valMiniature->bpv4;
|
||||
$bp_v6 = $valImage->bpv6 + $valMiniature->bpv6;
|
||||
$bp_all = $bp_v4 + $bp_v6;
|
||||
// Fix pour l'affichage des stats sans utilisation du service
|
||||
$bp_all = ($bp_all) ? $bp_all : 1;
|
||||
$bp_all += $bp_v6;
|
||||
// Nombre d'affichages
|
||||
$nb_view_all = $valImage->nbAff + $valMiniature->nbAff;
|
||||
// Taille totale
|
||||
|
@ -65,24 +60,27 @@ $size_all = $valImage->totSize + $valMiniature->totSize;
|
|||
<div class="card-body">
|
||||
<ul>
|
||||
<li>
|
||||
<?= number_format($valImage->nb, 0, ',', ' ') ?> images et
|
||||
<?= number_format($valMiniature->nb, 0, ',', ' ') ?> miniatures actuellement hébergées
|
||||
<?= number_format($valImage->nbTot, 0, ',', ' ') ?> images hébergées au total.
|
||||
</li>
|
||||
<li>
|
||||
<?= number_format($size_all / 1073741824, 1, ',', ' ') ?> Go de fichiers stockés
|
||||
<?= number_format($valImage->nb, 0, ',', ' ') ?> images et
|
||||
<?= number_format($valMiniature->nb, 0, ',', ' ') ?> miniatures actuellement hébergées.
|
||||
</li>
|
||||
<li>
|
||||
<?= number_format($size_all / 1073741824, 1, ',', ' ') ?> Go de fichiers actuellement stockés.
|
||||
</li>
|
||||
<li>
|
||||
<?= number_format($bp_all / 1073741824, 1, ',', ' ') ?> Go de trafic - dont
|
||||
<?= number_format(($bp_v6 / $bp_all) * 100, 2) ?>%
|
||||
en <a href="http://fr.wikipedia.org/wiki/Ipv6">IPv6</a>
|
||||
en <a href="https://fr.wikipedia.org/wiki/Ipv6">IPv6</a>.
|
||||
</li>
|
||||
<li>
|
||||
<?= number_format($nb_view_all, 0, ',', ' ') ?> affichages d'images
|
||||
<em>(<?= number_format($valImage->nbAff, 0, ',', ' ') ?> images
|
||||
+ <?= number_format($valMiniature->nbAff, 0, ',', ' ') ?> miniatures)</em>
|
||||
+ <?= number_format($valMiniature->nbAff, 0, ',', ' ') ?> miniatures)</em>.
|
||||
</li>
|
||||
<li>
|
||||
<?= $valMembre->nb ?> membres possèdant au total <?= $valPossede->nb ?> images
|
||||
<?= $valMembre->nb ?> membres possèdant au total <?= $valPossede->nb ?> images.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|