Compare commits

..

No commits in common. "master" and "v2.0.4" have entirely different histories.

142 changed files with 5878 additions and 9634 deletions

View file

@ -1,30 +0,0 @@
# This is a basic workflow to help you get started with Actions
name: PHP_CodeSniffer - Qualité du code
# Controls when the action will run.
# 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:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# 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@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
tools: cs2pr, phpcs
- name: Run phpcs
run: |
phpcs --version
phpcs -q --standard=$GITHUB_WORKSPACE/.phpcs_ruleset.xml --report=checkstyle $GITHUB_WORKSPACE | cs2pr

View file

@ -1,57 +0,0 @@
name: PHPUnit - Tests de l'application
on: [ push, pull_request, workflow_dispatch ]
jobs:
run:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ '8.3', '8.4' ]
name: PHP ${{ matrix.php-versions }}
steps:
- name: Checkout
uses: actions/checkout@v4
- 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 systemctl start mysql.service
- 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: 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/

1
.gitignore vendored
View file

@ -1,4 +1,3 @@
/.idea/
/config/config.php
/nbproject/
/template/css/monSite.css

View file

@ -1,5 +1,5 @@
#/*
#* Copyright 2008-2024 Anael MOBILIA
#* Copyright 2008-2017 Anael Mobilia
#*
#* This file is part of image-heberg.fr.
#*
@ -23,27 +23,30 @@ Options -Indexes
# Ré-écriture d'URL
RewriteEngine On
# Redirection systématique - si requise - vers **www**.image-heberg.fr
# Redirection systématique - si requise - vers www.image-heberg.fr
# HTTPS
RewriteCond %{HTTPS} on
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]
# 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]
# Protection des répertoires classes, config, cron, __tests
# Protection des répertoires classes, config, __tests, includes
RewriteCond %{REQUEST_URI} ^/classes/ [OR]
RewriteCond %{REQUEST_URI} ^/config/ [OR]
RewriteCond %{REQUEST_URI} ^/cron/ [OR]
RewriteCond %{REQUEST_URI} ^/__tests/
RewriteCond %{REQUEST_URI} ^/__tests/ [OR]
RewriteCond %{REQUEST_URI} ^/includes/
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]
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]

View file

@ -1,20 +0,0 @@
<?xml version="1.0"?>
<ruleset name="myRuleset">
<description>Regles pour le projet.</description>
<!-- Ne pas traiter les fichiers minifiés -->
<exclude-pattern>*.min.*</exclude-pattern>
<!-- Inclure PSR-12 -->
<rule ref="PSR12">
<!-- Exclure les CRLF (gérés par git => core.autocrlf=true ) -->
<exclude name="Generic.Files.LineEndings.InvalidEOLChar" />
<!-- Exclure la longueur des lignes -->
<exclude name="Generic.Files.LineLength.TooLong" />
</rule>
<!-- 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>

86
.travis.yml Normal file
View file

@ -0,0 +1,86 @@
#/*
# * Copyright 2008-2019 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/>
# */
# Language
language: php
# Versions de PHP testées
matrix:
include:
- php: 5.6
- php: 7.0
- php: 7.1
- php: 7.2
- php: 7.3
- php: nightly
allow_failures:
- php: 7.2
- php: 7.3
- php: nightly
# Autres prérequis
services:
- mysql
# Créer la BDD avant de commencer
before_script:
# Version de mysql
- mysql -V
# Création de la BDD
- mysql -e "CREATE DATABASE imageheberg;"
# Injection des tables de base
- mysql imageheberg < database.sql
# Copie du fichier de configuration
- sh -c "mv __tests/config/config.php config/"
# Insertion d'un jeu de données de test
- mysql imageheberg < __tests/data.sql
jobs:
include:
- php: 5.6
script:
- phpunit --version
- phpunit --colors --debug __tests/
- php: 7.0
script:
- wget https://phar.phpunit.de/phpunit-6.phar
- chmod +x phpunit-6.phar
- ./phpunit-6.phar --version
- ./phpunit-6.phar --colors --debug __tests/
- php: 7.1
script:
- wget https://phar.phpunit.de/phpunit-7.phar
- chmod +x phpunit-7.phar
- ./phpunit-7.phar --version
- ./phpunit-7.phar --colors --debug __tests/
- php: 7.2
script:
- phpunit --version
- phpunit --colors --debug __tests/
- php: 7.3
script:
- phpunit --version
- phpunit --colors --debug __tests/
- php: nightly
script:
- phpunit --version
- phpunit --colors --debug __tests/

View file

@ -1,11 +1,11 @@
[![Build Status](https://travis-ci.org/AnaelMobilia/image-heberg.fr.svg?branch=master)](https://travis-ci.org/AnaelMobilia/image-heberg.fr)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/d61a46162db94e0b8a053f4bb5dbc62f)](https://www.codacy.com/app/AnaelMobilia/image-heberg-fr?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=AnaelMobilia/image-heberg.fr&amp;utm_campaign=Badge_Grade)
# image-heberg.fr
Service d'hébergement d'images en ligne
# Configuration requise
- PHP 8.3 [*(Préférez une version de PHP maintenue !)*](https://www.php.net/supported-versions.php)
- Imagick
- MySQL ou MariaDB
- PHP 5.6, 7.0 ou 7.1
- MySQL
- Serveur web gérant les fichiers .htaccess
# Installation
@ -13,21 +13,11 @@ 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 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)
- 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/)
- Télécharger le fichier bootstrap.min.css
- Remplacer le contenu du fichier templates/css/boostrap-x.y.z.min.css par le fichier téléchargé
- Si souhaité, ajouter du code CSS spécifique dans le fichier templates/css/monSite.css
- 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 !)
# Stockage des images
- Les images sont stockées dans le répertoire /files ou /files/thumbs en fonction de leur type.
- Chaque image est stockée sous le nom du md5 de son fichier d'origine (correspondance en BDD)
- Pour limiter le nombre de fichiers par répertoire, chaque image est stockée dans un sous répertoire qui est la première lettre de son md5
- Chaque image est stockée sous forme de md5 (correspondance en BDD)
- Pour limiter le nombre de fichiers par répertoire, chaque image est stockée dans un sous répertoire qui est la première lettre de son md5

View file

@ -1,455 +0,0 @@
<?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 ImageHebergTests;
use ImageHeberg\HelperAbuse;
use ImageHeberg\ImageObject;
use ImageHeberg\HelperAdmin;
use ImageHeberg\RessourceObject;
use ImageHeberg\UtilisateurObject;
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
use PHPUnit\Framework\TestCase;
class AbuseTest extends TestCase
{
/**
* Signalement d'une image
*/
#[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'] = 'https://www.example.com/files/image_15.png';
ob_start();
require 'abuse.php';
ob_end_clean();
$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'
);
}
/**
* 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)
);
}
}

View file

@ -1,139 +0,0 @@
<?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 ImageHebergTests;
use ImageHeberg\RessourceObject;
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
use PHPUnit\Framework\TestCase;
class DisplayPicsTest extends TestCase
{
/**
* Affichage d'une image inexistante
*/
#[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'
);
}
/**
* Affichage d'une image inexistante
*/
#[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'
);
}
/**
* Affichage d'une image inexistante
*/
#[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'
);
}
/**
* Affichage d'une image bloquée
*/
#[RunInSeparateProcess]
public function testImageBloquee(): void
{
require 'config/config.php';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_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'
);
}
/**
* Affichage d'une image signaléee
*/
#[RunInSeparateProcess]
public function testImageSignalee(): void
{
require 'config/config.php';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_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'
);
}
}

View file

@ -1,278 +0,0 @@
<?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 ImageHebergTests;
use ImageHeberg\ImageObject;
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];
/**
* 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
*/
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();
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
);
// Calcul des dimensions théoriques
$indiceLargeur = (($unAngle % 180) === 0 ? 0 : 1);
$indiceHauteur = (($unAngle % 180) === 0 ? 1 : 0);
// 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
);
// 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
*/
#[RunInSeparateProcess]
public function testRedimensionnementImages(): void
{
require 'config/config.php';
$monImage = new ImageObject();
/*
* Cas incohérents => Ne rien faire
*/
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 800),
'Pas d\'agrandissement'
);
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 601, 800),
'Pas d\'agrandissement'
);
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 801),
'Pas d\'agrandissement'
);
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 599, 800),
'Pas d\'agrandissement'
);
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 799),
'Pas d\'agrandissement'
);
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 0, 799),
'Image de taille zéro'
);
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 0, 0),
'Image de taille zéro'
);
$this->assertFalse(
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 10, 0),
'Image de taille zéro'
);
/*
* Format portrait
*/
// Doit être 200x267
$monImage->redimensionner(
_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png',
_PATH_TESTS_OUTPUT_ . 'image_portrait_200x400.png',
200,
400
);
$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
$monImage->redimensionner(
_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png',
_PATH_TESTS_OUTPUT_ . 'image_portrait_400x200.png',
400,
200
);
$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'
);
/*
* Format paysage
*/
// Doit être 267x200
$monImage->redimensionner(
_PATH_TESTS_IMAGES_ . 'image_paysage_800x600.png',
_PATH_TESTS_OUTPUT_ . 'image_paysage_400x200.png',
400,
200
);
$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
$monImage->redimensionner(
_PATH_TESTS_IMAGES_ . 'image_paysage_800x600.png',
_PATH_TESTS_OUTPUT_ . 'image_paysage_200x400.png',
200,
400
);
$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'
);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,392 +0,0 @@
<?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 ImageHebergTests;
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 mixed
*/
public function getConnection(): mixed
{
$pdo = new PDO('sqlite::memory:');
return $this->createDefaultDBConnection($pdo, ':memory:');
}
/**
* Fonction requise par l'extension Database
* @return PHPUnit_Extensions_Database_DataSet_DefaultDataSet
*/
public function getDataSet(): PHPUnit_Extensions_Database_DataSet_DefaultDataSet
{
return new PHPUnit_Extensions_Database_DataSet_DefaultDataSet();
}
public function testConnexionMembreExistant(): void
{
// Chargement de la configuration
require_once 'config/config.php';
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['valider'] = 1;
$_POST['userName'] = 'admin';
$_POST['userPassword'] = 'password';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Appel de la page
*/
ob_start();
require 'membre/connexionCompte.php';
ob_end_clean();
/**
* Vérification des valeurs
*/
$maSession = new SessionObject();
$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(): void
{
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['valider'] = 1;
$_POST['userName'] = 'admin';
$_POST['userPassword'] = 'monPassword';
$_POST['userMail'] = 'myMail@example.com';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SESSION['flag'] = true;
/**
* Appel de la page
*/
ob_start();
require 'membre/creerCompte.php';
ob_end_clean();
/**
* Vérification des valeurs
*/
$monMembre = new UtilisateurObject();
$this->assertFalse(
$monMembre->connexion($_POST['userName'], $_POST['userPassword']),
'connexion : le nom d\'utilisateur doit être unique'
);
}
/**
* Création d'un compte membre.
*/
#[Depends('testMembreCreerCompteDoublon')]
public function testMembreCreerCompte(): void
{
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['valider'] = 1;
$_POST['userName'] = 'username';
$_POST['userPassword'] = 'password';
$_POST['userMail'] = 'myMail@example.com';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SESSION['flag'] = true;
/**
* Appel de la page
*/
ob_start();
require 'membre/creerCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new UtilisateurObject(3);
/**
* Vérification des valeurs
*/
// Email
$this->assertEquals(
'mymail@example.com',
$monMembre->getEmail(),
'Vérification email'
);
// ID
$this->assertEquals(
3,
$monMembre->getId()
);
// @ IP d'inscription
$this->assertEquals(
'127.0.0.1',
$monMembre->getIpInscription()
);
// Niveau de droits
$this->assertEquals(
UtilisateurObject::LEVEL_USER,
$monMembre->getLevel()
);
// Nom
$this->assertEquals(
'username',
$monMembre->getUserName()
);
$this->assertTrue(
$monMembre->connexion($_POST['userName'], $_POST['userPassword'])
);
}
/**
* Modification du mail
*/
#[Depends('testMembreCreerCompte')]
public function testMembreModifierMail(): void
{
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['modifierMail'] = 1;
$_POST['userPasswordMail'] = 'password';
$_POST['userMail'] = 'john.doe@example.com';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new UtilisateurObject();
$this->assertTrue(
$unMembre->connexion('username', $_POST['userPasswordMail']),
'connexion avant'
);
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération de l'utilisateur
*/
$monMembre = new UtilisateurObject(3);
/**
* Vérification des valeurs
*/
// Email
$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(): void
{
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['modifierPwd'] = 1;
$_POST['oldUserPassword'] = 'password';
$_POST['newUserPassword'] = 'monPassword';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new UtilisateurObject();
$this->assertTrue(
$unMembre->connexion('username', $_POST['oldUserPassword']),
'connexion avant'
);
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new UtilisateurObject();
/**
* Vérification des valeurs
*/
$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(): void
{
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['supprimerCompte'] = 1;
$_POST['userPasswordDelete'] = 'monPassword';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new UtilisateurObject();
$this->assertTrue(
$unMembre->connexion('username', $_POST['userPasswordDelete']),
'connexion avant'
);
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new UtilisateurObject();
/**
* Vérification des valeurs
*/
$this->assertTrue(
$monMembre->connexion('username', $_POST['userPasswordDelete']),
'connexion devrait être possible'
);
}
/**
* Suppression du compte
*/
#[Depends('testMembreSupprimerCompteRequiertCheckbox')]
public function testMembreSupprimerCompte(): void
{
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['supprimerCompte'] = 1;
$_POST['userPasswordDelete'] = 'monPassword';
$_POST['confirmeDelete'] = 1;
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new UtilisateurObject();
$this->assertTrue(
$unMembre->connexion('username', $_POST['userPasswordDelete']),
'connexion avant'
);
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new UtilisateurObject();
/**
* Vérification des valeurs
*/
$this->assertFalse(
$monMembre->connexion('username', $_POST['userPasswordDelete']),
'connexion ne devrait plus être possible'
);
}
/**
* Connexion au compte créé lors de la création de la BDD
*/
#[Depends('testMembreSupprimerCompte')]
public function testConnexionCompteHistorique(): void
{
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Récupération d'un objet
*/
$monMembre = new UtilisateurObject();
/**
* Vérification des valeurs
*/
$this->assertTrue(
$monMembre->connexion('admin', 'password'),
'connexion au compte créé à l\'import de la BDD devrait être possible'
);
}
}

View file

@ -1,98 +0,0 @@
<?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
__tests/_nbImages Normal file
View file

@ -0,0 +1 @@
8

1
__tests/_nbPossede Normal file
View file

@ -0,0 +1 @@
4

1
__tests/_nbThumbnails Normal file
View file

@ -0,0 +1 @@
2

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -19,89 +19,60 @@
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
*/
/*
/**
* CHAMPS A CONFIGURER
*/
/* Base de données */
// Serveur de base de données
const _BDD_HOST_ = 'localhost';
define('_BDD_HOST_', 'localhost');
// Utilisateur SQL
const _BDD_USER_ = 'root';
define('_BDD_USER_', 'root');
// Mot de passe SQL
const _BDD_PASS_ = 'root';
define('_BDD_PASS_', '');
// Nom de la base de données
const _BDD_NAME_ = 'imageheberg';
define('_BDD_NAME_', 'imageheberg');
/* Système de fichiers */
// Emplacement de votre site sur le système de fichiers de votre hébergeur
const _PATH_ = '/home/runner/work/image-heberg.fr/image-heberg.fr/';
define('_PATH_', '/home/travis/build/AnaelMobilia/image-heberg.fr/');
/* A propos de l'outil */
// Nom affiché du service
const _SITE_NAME_ = 'monSite';
define('_SITE_NAME_', 'monSite');
// URL du site
const _BASE_URL_ = 'www.example.com/';
define('_BASE_URL_', 'www.example.com/');
// Administrateur du site
const _ADMINISTRATEUR_NOM_ = 'John DOE';
define('_ADMINISTRATEUR_NOM_', 'John DOE');
// Site web de l'administrateur
const _ADMINISTRATEUR_SITE_ = '//www.example.com/';
define('_ADMINISTRATEUR_SITE_', '//www.example.com/');
// Mail de l'administrateur (non affiché)
const _ADMINISTRATEUR_EMAIL_ = 'john.doe@example.com';
define('_ADMINISTRATEUR_EMAIL_', 'john.doe@example.com');
/* Informations légales */
// Hébergeur du site
const _HEBERGEUR_NOM_ = 'OVH';
define('_HEBERGEUR_NOM_', 'OVH');
// Site web de l'hébergeur
const _HEBERGEUR_SITE_ = '//www.ovh.com';
define('_HEBERGEUR_SITE_', '//www.ovh.com');
/* Configurations spécifiques de l'outil */
// Poids maximal des fichiers
const _IMAGE_POIDS_MAX_ = 5242880;
define('_IMAGE_POIDS_MAX_', 5242880);
// Délai de conservation d'une image jamais affichée (en jours)
const _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ = 7;
define('_DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_', 7);
// Délai depuis le dernier affichage d'une image avant de la supprimer (en jours)
const _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ = 365;
define('_DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_', 365);
// Volume maximal de stockage d'images (en Go)
const _QUOTA_MAXIMAL_IMAGES_GO_ = 90;
define('_QUOTA_MAXIMAL_IMAGES_GO_', 90);
// Affichage des messages d'erreur
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'];
define('_DEBUG_', TRUE);
/**
* FIN DES CHAMPS A CONFIGURER
*/
/**
* CHAMPS A COMPLETER UNIQUEMENT SI VOUS AVIEZ INSTALLE UNE VERSION ANTERIEURE A v2.0.4
*/
// Salt pour les mots de passe
// Legacy - n'est plus requis !!
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
const _PHPUNIT_ = true;
define('_TRAVIS_', TRUE);
require _PATH_ . 'config/image-heberg.php';

View file

@ -1,5 +1,5 @@
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -19,109 +19,41 @@
--
-- 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
(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');
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);
--
-- Images à supprimer
--
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');
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);
--
-- Image signalé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
(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');
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
(15, '127.0.0.1', '2008-01-01 00:00:00', 'imageSignalee.png', 'imageSignalee.png', 4239, 400, 640, NULL, 0, 0, 'd456d1b6582a15f0f458006898b40e29', 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`, `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');
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');
--
-- Possessions
--
INSERT INTO `possede` (`images_id`, `membres_id`) VALUES ('11', '2'),
INSERT INTO `possede` (`image_id`, `pk_membres`) VALUES ('11', '2'),
('14', '1');
--
-- Second compte utilisateur
--
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, '');
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);

View file

@ -0,0 +1,94 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
use PHPUnit\Framework\TestCase;
class displayPicsTest extends TestCase {
/**
* Affichage d'une image inexistante
* @runInSeparateProcess
*/
public function testImageInexistante() {
$_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");
}
/**
* Affichage d'une image inexistante
* @runInSeparateProcess
*/
public function testMiniatureInexistante() {
$_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");
}
/**
* Affichage d'une image inexistante
* @runInSeparateProcess
*/
public function testRépertoireInexistant() {
$_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");
}
/**
* Affichage d'une image bloquée
* @runInSeparateProcess
*/
public function testImageBloquee() {
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['REQUEST_URI'] = 'files/imageBloquee.jpg';
ob_start();
require 'displayPics.php';
ob_end_clean();
/* @var $monObjet ressourceObject */
$this->assertEquals(_IMAGE_BAN_, $monObjet->getNomNouveau(), "image_ban si image bloquée");
}
/**
* Affichage d'une image signaléee
* @runInSeparateProcess
*/
public function testImageSignalee() {
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['REQUEST_URI'] = 'files/imageSignalee.png';
ob_start();
require 'displayPics.php';
ob_end_clean();
/* @var $monObjet ressourceObject */
$this->assertEquals(_IMAGE_BAN_, $monObjet->getNomNouveau(), "image_ban si image signalée");
}
}

164
__tests/imageObjectTest.php Normal file
View file

@ -0,0 +1,164 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
use PHPUnit\Framework\TestCase;
class imageObjectTest extends TestCase {
/**
* Rotation des images
* @runInSeparateProcess
*/
public function testRotationImages() {
require 'config/config.php';
$monImage = new imageObject();
// JPG
$angle = 90;
$monImage->rotation($angle, _PATH_TESTS_IMAGES_ . 'image_banned.jpg', _PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.jpg-' . $angle . '-jusqua-php-7.1', _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);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.jpg-' . $angle . '-jusqua-php-7.1', _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);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.jpg-' . $angle . '-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_banned.jpg-' . $angle, "Rotation JPG " . $angle);
}
// PNG
$angle = 90;
$monImage->rotation($angle, _PATH_TESTS_IMAGES_ . 'image_banned.png', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.png-' . $angle . '-a-partir-php-7.2', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle, "Rotation PNG " . $angle);
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.png-' . $angle . '-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle, "Rotation PNG " . $angle);
}
$angle = 180;
$monImage->rotation($angle, _PATH_TESTS_IMAGES_ . 'image_banned.png', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.png-' . $angle . '-a-partir-php-7.2', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle, "Rotation PNG " . $angle);
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.png-' . $angle . '-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle, "Rotation PNG " . $angle);
}
$angle = 270;
$monImage->rotation($angle, _PATH_TESTS_IMAGES_ . 'image_banned.png', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.png-' . $angle . '-a-partir-php-7.2', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle, "Rotation PNG " . $angle);
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.png-' . $angle . '-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_banned.png-' . $angle, "Rotation PNG " . $angle);
}
// GIF
$angle = 90;
$monImage->rotation($angle, _PATH_TESTS_IMAGES_ . 'image_banned.gif', _PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.gif-' . $angle . '-jusqua-php-7.1', _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);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.gif-' . $angle . '-jusqua-php-7.1', _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);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_banned.gif-' . $angle . '-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_banned.gif-' . $angle, "Rotation GIF " . $angle);
}
}
/**
* Redimensionnement des images
* @runInSeparateProcess
*/
public function testRedimensionnementImages() {
require 'config/config.php';
$monImage = new imageObject();
/**
* Cas NULL
*/
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 800), "Pas d'agrandissement");
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 601, 800), "Pas d'agrandissement");
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 801), "Pas d'agrandissement");
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 599, 800), "Pas d'agrandissement");
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 600, 799), "Pas d'agrandissement");
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 0, 799), "Image de taille zéro");
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 0, 0), "Image de taille zéro");
$this->assertEquals(NULL, $monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', '', 10, 0), "Image de taille zéro");
/**
* Format portrait
*/
// Doit être 200x267
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', _PATH_TESTS_OUTPUT_ . 'image_portrait_200x400.png', 200, 400);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_portrait_200x400.png-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_portrait_200x400.png', "Redimensionnement portrait 200x400");
}
// Doit être 150x200
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_portrait_600x800.png', _PATH_TESTS_OUTPUT_ . 'image_portrait_400x200.png', 400, 200);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_portrait_400x200.png-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_portrait_400x200.png', "Redimensionnement portrait 400x200");
}
/**
* Format paysage
*/
// Doit être 267x200
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_paysage_800x600.png', _PATH_TESTS_OUTPUT_ . 'image_paysage_400x200.png', 400, 200);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_paysage_400x200.png-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_paysage_400x200.png', "Redimensionnement paysage 400x200");
}
// Doit être 200x150
$monImage->redimensionner(_PATH_TESTS_IMAGES_ . 'image_paysage_800x600.png', _PATH_TESTS_OUTPUT_ . 'image_paysage_200x400.png', 200, 400);
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
} else {
$this->assertFileEquals(_PATH_TESTS_IMAGES_ . 'image_paysage_200x400.png-jusqua-php-7.1', _PATH_TESTS_OUTPUT_ . 'image_paysage_200x400.png', "Redimensionnement paysage 200x400");
}
}
}

View file

@ -0,0 +1,905 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
use PHPUnit\Framework\TestCase;
class imageUploadAndDeleteTest extends TestCase {
// Fichiers pour le nombre d'images / possessions attendues
const fichierImage = '../_nbImages';
const fichierMiniature = '../_nbThumbnails';
const fichierPossede = '../_nbPossede';
/**
* Nombre d'images en BDD
* @return int
*/
private static function countImagesEnBdd() {
$maReq = maBDD::getInstance()->query("SELECT COUNT(*) AS nb FROM images");
$result = $maReq->fetch();
return $result->nb;
}
/**
* Nombre de miniatures en BDD
* @return int
*/
private static function countMiniaturesEnBdd() {
$maReq = maBDD::getInstance()->query("SELECT COUNT(*) AS nb FROM thumbnails");
$result = $maReq->fetch();
return $result->nb;
}
/**
* Nombre d'images POSSEDEES en BDD
* @return int
*/
private static function countImagesPossedeesEnBdd() {
$maReq = maBDD::getInstance()->query("SELECT COUNT(*) AS nb FROM possede");
$result = $maReq->fetch();
return $result->nb;
}
/**
* Nombre d'éléments présents dans le fichier
* @param string $nomFichier nom du fichier
* @return int nb éléments
*/
private static function getNb($nomFichier) {
$f = fopen(_PATH_TESTS_IMAGES_ . $nomFichier, 'r');
$val = fread($f, 10);
fclose($f);
return $val;
}
/**
* Ecrit une valeur dans le fichier
* @param string $nomFichier
* @param int $valeur
*/
private static function setNb($nomFichier, $valeur) {
$f = fopen(_PATH_TESTS_IMAGES_ . $nomFichier, 'w');
fwrite($f, $valeur);
fclose($f);
}
/**
* $val--
* @param string $nomFichier
*/
private static function setNbMoins($nomFichier) {
$val = self::getNb($nomFichier);
self::setNb($nomFichier, --$val);
}
/**
* $val++
* @param string $nomFichier
*/
private static function setNbPlus($nomFichier) {
$val = self::getNb($nomFichier);
self::setNb($nomFichier, ++$val);
}
/**
* Test de l'envoi simple : présence BDD et HDD
*/
public function testEnvoi() {
require_once 'config/config.php';
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_banned.gif';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Envoi image ne doit pas être bloqué dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Envoi image ne doit pas être bloqué dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Envoi image doit créer d'image en BDD");
$this->assertEquals(TRUE, file_exists(_PATH_IMAGES_ . '6/6a9dd81ae12c79d953031bc54c07f900'), "Envoi image doit créer d'image sur HDD");
}
/**
* Test de l'envoi avec miniature : présence BDD et HDD
* @depends testEnvoi
*/
public function testEnvoiMiniature() {
require_once 'config/config.php';
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_pour_miniature.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
$_POST['dimMiniature'] = '50x50';
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Envoi image + miniature ne doit pas être bloqué dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Envoi image + miniature ne doit pas être bloqué dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Envoi image + miniature doit créer image en BDD");
self::setNbPlus(self::fichierMiniature);
$this->assertEquals(self::countMiniaturesEnBdd(), self::getNb(self::fichierMiniature), "Envoi image + miniature doit créer miniature en BDD");
$this->assertEquals(TRUE, file_exists(_PATH_IMAGES_ . 'f/f653f58431521a201fdc23451c9a8af6'), "Envoi image + miniature doit créer image sur HDD");
$this->assertEquals(TRUE, file_exists(_PATH_MINIATURES_ . 'e/ee5acdecd9894734e685b019662e6959'), "Envoi image + miniature doit créer miniature sur HDD");
}
/**
* Test de l'envoi avec miniature ET rotation : présence BDD et HDD
* @depends testEnvoiMiniature
*/
public function testEnvoiMiniatureRotation() {
require_once 'config/config.php';
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_pour_miniature2.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
$_POST['dimMiniature'] = '50x50';
$_POST['angleRotation'] = 90;
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Envoi image + miniature (rotation) ne doit pas être bloqué dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Envoi image + miniature (rotation) ne doit pas être bloqué dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Envoi image + miniature (rotation) doit créer image en BDD");
self::setNbPlus(self::fichierMiniature);
$this->assertEquals(self::countMiniaturesEnBdd(), self::getNb(self::fichierMiniature), "Envoi image + miniature (rotation) doit créer miniature en BDD");
$this->assertEquals(TRUE, file_exists(_PATH_IMAGES_ . '4/4a3da533b304629c3ef35ece7fb01308'), "Envoi image + miniature (rotation) doit créer image sur HDD");
$this->assertEquals(TRUE, file_exists(_PATH_MINIATURES_ . '8/8c3b9bd4f7339b9ed4e1aee52cf8b55f'), "Envoi image + miniature (rotation) doit créer miniature sur HDD");
}
/**
* Test du renvoi d'une image mais avec demande de création d'une miniature
* @depends testEnvoiMiniatureRotation
*/
public function testRenvoiImageDemandeMiniature() {
require_once 'config/config.php';
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_banned2.gif';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
$_POST['dimMiniature'] = '50x50';
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Renvoi image - dde miniature - ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Renvoi image - dde miniature - ne doit pas être bloquée dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Renvoi image - dde miniature - doit être bloquée en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Renvoi image - dde miniature (possède) - doit être bloquée en BDD");
self::setNbPlus(self::fichierMiniature);
$this->assertEquals(self::countMiniaturesEnBdd(), self::getNb(self::fichierMiniature), "Renvoi image - dde miniature - doit créer miniature en BDD");
$this->assertEquals(TRUE, file_exists(_PATH_MINIATURES_ . 'b/b8269be7be4e1d804cd5b82d9734bab7'), "Renvoi image - dde miniature - doit créer miniature sur HDD");
}
/**
* Test du renvoi d'une image avec miniature mais demande demande de création d'une autre miniature
* @depends testRenvoiImageDemandeMiniature
*/
public function testRenvoiImageDemandeNouvelleMiniature() {
require_once 'config/config.php';
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_banned3.gif';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
$_POST['dimMiniature'] = '40x40';
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Renvoi image - dde NOUVELLE miniature - ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Renvoi image - dde NOUVELLE miniature - ne doit pas être bloquée dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Renvoi image - dde NOUVELLE miniature - doit être bloquée en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Renvoi image - dde NOUVELLE miniature - doit être bloquée en BDD");
self::setNbPlus(self::fichierMiniature);
$this->assertEquals(self::countMiniaturesEnBdd(), self::getNb(self::fichierMiniature), "Renvoi image - dde NOUVELLE miniature - doit créer miniature en BDD");
$this->assertEquals(TRUE, file_exists(_PATH_MINIATURES_ . '0/0aa6219e66d00bb17a3b3f10da7e3a12'), "Renvoi image - dde NOUVELLE miniature - doit créer miniature sur HDD");
}
/**
* Envoi sans affichage page index.php
* @depends testRenvoiImageDemandeNouvelleMiniature
*/
public function testEnvoiBrut() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Non affichage du formulaire d'upload devrait être détecté dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Non affichage du formulaire d'upload devrait être détecté dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Non affichage du formulaire d'upload ne doit pas créer d'image en BDD");
}
/**
* Envoi sans fichierU
* @depends testEnvoiBrut
*/
public function testEnvoiSansFichier() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Absence de fichier envoyé devrait être détecté dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Absence de fichier envoyé devrait être détecté dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Absence de fichier envoyé ne doit pas créer d'image en BDD");
}
/**
* Fichier trop lourd
* @depends testEnvoiSansFichier
*/
public function testEnvoiGrosFichier() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['name'] = 'nomFichier';
$_FILES['fichier']['size'] = _IMAGE_POIDS_MAX_ + 1;
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Fichier trop gros devrait être détecté dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Fichier trop gros devrait être détecté dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Fichier trop gros ne doit pas créer d'image en BDD");
}
/**
* Type Mime : envoi d'un fichier doc
* @depends testEnvoiGrosFichier
*/
public function testTypeMimePasUneImage() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'fichier_doc.doc';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Type mime : pas une image doit être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Type mime : pas une image doit être bloquée dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "type mime : pas une image doit être bloquée en BDD");
}
/**
* Type Mime : mauvais type de fichier (DOC).jpg
* @depends testTypeMimePasUneImage
*/
public function testTypeMimeMauvaisTypeFichier() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'fichier_doc.jpg';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Type mime : fausse image doit être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Type mime : fausse image doit être bloquée dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "type mime : fausse image doit être bloquée en BDD");
}
/**
* Type Mime : mauvaise extension (JPG).png
* @depends testTypeMimeMauvaisTypeFichier
*/
public function testTypeMimeMauvaiseExtension() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_jpg.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Type mime : extension incorrecte ne doit pas poser de soucis dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Type mime : extension incorrecte ne doit pas poser de soucis dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Type mime : extension incorrecte ne doit pas être bloquée en BDD");
}
/**
* Dimensions de l'image - Très large
* @depends testTypeMimeMauvaiseExtension
*/
public function testTresLarge() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_tres_large.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Image 10000x1 ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Image 10000x1 ne doit pas être bloquée dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Image 10000x1 ne doit pas être bloquée en BDD");
}
/**
* Dimensions de l'image - Très haute
* @depends testTresLarge
*/
public function testTresHaute() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_tres_haute.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Image 1x10000 ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Image 1x10000 ne doit pas être bloquée dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Image 1x10000 ne doit pas être bloquée en BDD");
}
/**
* Dimensions de l'image - Trop grande
* @depends testTresHaute
*/
public function testTropGrande() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_10000x10000.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Image 10000x10000 doit être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Image 10000x10000 doit être bloquée dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Image 10000x10000 doit être bloquée en BDD");
}
/**
* Envoi d'une image authentifié
* @depends testTropGrande
*/
public function testEnvoiImageAuthentifie() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_authentifie.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
/**
* Authentification
*/
$unMembre = new utilisateurObject();
$unMembre->connexion('admin', 'password');
ob_start();
require 'upload.php';
ob_end_clean();
/**
* Désauthentification
*/
$maSession = new sessionObject();
$maSession->deconnexion();
$this->assertEquals(empty($msgErreur), TRUE, "Envoi image authentifié ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Envoi image authentifié ne doit pas être bloquée dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Envoi image authentifié ne doit pas être bloquée en BDD");
self::setNbPlus(self::fichierPossede);
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Envoi image authentifié ne doit pas être bloquée en BDD");
}
/**
* Renvoi d'une image - Anonyme / Anonyme
* @depends testEnvoiImageAuthentifie
*/
public function testRenvoiImageAnonymeAnonyme() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_tres_haute.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Renvoi image doit être bloquée en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Renvoi image doit être bloquée en BDD");
}
/**
* Renvoi d'une image - Anonyme / Authentifié
* @depends testRenvoiImageAnonymeAnonyme
*/
public function testRenvoiImageAnonymeAuthentifie() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_tres_haute.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
/**
* Authentification
*/
$unMembre = new utilisateurObject();
$unMembre->connexion('admin', 'password');
ob_start();
require 'upload.php';
ob_end_clean();
/**
* Désauthentification
*/
$maSession = new sessionObject();
$maSession->deconnexion();
$this->assertEquals(empty($msgErreur), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Renvoi image ne doit pas être bloquée en BDD");
self::setNbPlus(self::fichierPossede);
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Renvoi image ne doit pas être bloquée en BDD");
}
/**
* Renvoi d'une image - Authentifié / Anonyme
* @depends testRenvoiImageAnonymeAuthentifie
*/
public function testRenvoiImageAuthentifieAnonyme() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_authentifie.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Renvoi image ne doit pas être bloquée en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Renvoi image doit être bloquée en BDD");
}
/**
* Renvoi d'une image - Authentifié / Authentifié
* @depends testRenvoiImageAuthentifieAnonyme
*/
public function testRenvoiImageAuthentifieAuthentifie() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_authentifie.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
/**
* Authentification
*/
$unMembre = new utilisateurObject();
$unMembre->connexion('admin', 'password');
ob_start();
require 'upload.php';
ob_end_clean();
/**
* Désauthentification
*/
$maSession = new sessionObject();
$maSession->deconnexion();
$this->assertEquals(empty($msgErreur), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Renvoi image doit être bloquée en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Renvoi image doit être bloquée en BDD");
}
/**
* Renvoi d'une image - Authentifié / Authentifié Autrement
* @depends testRenvoiImageAuthentifieAuthentifie
*/
public function testRenvoiImageAuthentifieAuthentifie2() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_authentifie.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
/**
* Authentification
*/
$unMembre = new utilisateurObject();
$unMembre->connexion('user', 'password');
ob_start();
require 'upload.php';
ob_end_clean();
/**
* Désauthentification
*/
$maSession = new sessionObject();
$maSession->deconnexion();
$this->assertEquals(empty($msgErreur), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Renvoi image ne doit pas être bloquée dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Renvoi image ne doit pas être bloquée en BDD");
self::setNbPlus(self::fichierPossede);
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Renvoi image ne doit pas être bloquée en BDD");
}
/**
* Suppression d'une image inexistante
* @depends testRenvoiImageAuthentifieAuthentifie2
*/
public function testSuppressionImageInexistante() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_GET['id'] = 'fichierInexistant';
$_GET['type'] = ressourceObject::typeImage;
ob_start();
require 'delete.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Suppression image inexistante doit être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image inexistante doit être bloqué dans delete.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image inexistante doit être bloqué en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression image inexistante doit être bloqué en BDD");
}
/**
* Suppression d'une image - Propriétaire en étant Anonyme
* @depends testSuppressionImageInexistante
*/
public function testSuppressionImageProprietaireAnonyme() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_GET['id'] = '_image_404.png';
$_GET['type'] = ressourceObject::typeImage;
ob_start();
require 'delete.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Suppression image possédée par autrui doit être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image possédée par autrui doit être bloqué dans delete.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image possédée par autrui doit être bloqué en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression image possédée par autrui doit être bloqué en BDD");
}
/**
* Suppression d'une image - Propriétaire en étant Authentifié mais Autre
* @depends testSuppressionImageProprietaireAnonyme
*/
public function testSuppressionImageProprietaireAuthentifie2() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_GET['id'] = '_image_404.png';
$_GET['type'] = ressourceObject::typeImage;
/**
* Authentification
*/
$unMembre = new utilisateurObject();
$unMembre->connexion('user', 'password');
ob_start();
require 'delete.php';
ob_end_clean();
/**
* Désauthentification
*/
$maSession = new sessionObject();
$maSession->deconnexion();
$this->assertEquals(empty($msgErreur), FALSE, "Suppression image possédée par autrui doit être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image possédée par autrui doit être bloqué dans delete.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image possédée par autrui doit être bloqué en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression image possédée par autrui doit être bloqué en BDD");
}
/**
* Suppression d'une image - Propriétaire en étant Authentifié
* @depends testSuppressionImageProprietaireAuthentifie2
*/
public function testSuppressionImageProprietaireAuthentifie() {
unset($_POST);
unset($_FILES);
unset($_GET);
// Copie du fichier
rename(_PATH_TESTS_IMAGES_ . 'image_a_supprimer.png', _PATH_IMAGES_ . 'e/e656d1b6582a15f0f458006898b40e29');
$_SERVER['REMOTE_ADDR'] = '127.0.0.2';
$_GET['id'] = '100000019001334055750.png';
$_GET['type'] = ressourceObject::typeImage;
/**
* Authentification
*/
$unMembre = new utilisateurObject();
$unMembre->connexion('user', 'password');
ob_start();
require 'delete.php';
ob_end_clean();
/**
* Désauthentification
*/
$maSession = new sessionObject();
$maSession->deconnexion();
$this->assertEquals(empty($msgErreur), TRUE, "Suppression image possédée ne doit pas être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image possédée ne doit pas être bloqué dans delete.php");
self::setNbMoins(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image possédée ne doit pas être bloqué en BDD");
self::setNbMoins(self::fichierPossede);
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression image possédée ne doit pas être bloqué en BDD");
$this->assertEquals(file_exists(_PATH_IMAGES_ . 'e/e656d1b6582a15f0f458006898b40e29'), TRUE, "Suppression image possédée ne doit pas être effacé du HDD car encore en usage");
}
/**
* Suppression d'une image - Anonyme en étant hors délai
* @depends testSuppressionImageProprietaireAuthentifie
*/
public function testSuppressionImageAnonymeHorsDelai() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_GET['id'] = '146734019451334055750.png';
$_GET['type'] = ressourceObject::typeImage;
ob_start();
require 'delete.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Suppression image hors délai doit être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image hors délai doit être bloqué dans delete.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image hors délai doit être bloqué en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression image hors délai doit être bloqué en BDD");
}
/**
* Suppression d'une image - Anonyme en étant dans délai mais pas la bonne IP
* @depends testSuppressionImageProprietaireAuthentifie
*/
public function testSuppressionImageAnonymeDansDelaiMauvaiseIP() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.2';
$_GET['id'] = '147834019001334055750.png';
$_GET['type'] = ressourceObject::typeImage;
ob_start();
require 'delete.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), FALSE, "Suppression image dans délai par autre IP doit être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image dans délai par autre IP doit être bloqué dans delete.php");
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image dans délai par autre IP doit être bloqué en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression image dans délai par autre IP doit être bloqué en BDD");
}
/**
* Suppression d'une image - Anonyme en étant dans le délai
* @depends testSuppressionImageAnonymeDansDelaiMauvaiseIP
*/
public function testSuppressionImageAnonymeDansDelai() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.10';
$_GET['id'] = '147834019001334055750.png';
$_GET['type'] = ressourceObject::typeImage;
ob_start();
require 'delete.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Suppression image dans délai ne doit pas être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image dans délai ne doit pas être bloqué dans delete.php");
self::setNbMoins(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image dans délai ne doit pas être bloqué en BDD");
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression image dans délai ne doit pas être bloqué en BDD");
$this->assertEquals(file_exists(_PATH_IMAGES_ . 'e/e656d1b6582a15f0f458006898b40e29'), FALSE, "Suppression image dans délai doit être effacé du HDD");
}
/**
* Test de l'envoi simple avec redimensionnement : présence BDD et HDD
* @depends testSuppressionImageAnonymeDansDelai
*/
public function testEnvoiRedim() {
unset($_POST);
unset($_FILES);
unset($_GET);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_POST['Submit'] = 1;
$_SESSION['_upload'] = 1;
$_FILES['fichier']['size'] = 104857;
$_FILES['fichier']['name'] = 'image_paysage_800x600.png';
$_FILES['fichier']['tmp_name'] = _PATH_TESTS_IMAGES_ . $_FILES['fichier']['name'];
$_POST['redimImage'] = '400x200';
ob_start();
require 'upload.php';
ob_end_clean();
$this->assertEquals(empty($msgErreur), TRUE, "Envoi image avec redim ne doit pas être bloqué dans upload.php");
$this->assertEquals(empty($msgWarning), TRUE, "Envoi image avec redim ne doit pas être bloqué dans upload.php");
self::setNbPlus(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Envoi image avec redim doit créer d'image en BDD");
$this->assertEquals(TRUE, file_exists(_PATH_IMAGES_ . '4/43b604c3a5c18a161bc3a01bdb58ebf7'), "Envoi image avec redim doit créer image redim sur HDD");
$this->assertEquals(FALSE, file_exists(_PATH_IMAGES_ . '4/4db0b6f10d49fb1a8c2e8b8ff47cf3f6'), "Envoi image avec redim ne doit pas créer d'image originale sur HDD");
}
/**
* Test de la suppression d'une image avec plusieurs miniatures
* @depends testEnvoiRedim
*/
public function testSuppressionImagePlusieursMiniatures() {
unset($_POST);
unset($_FILES);
unset($_GET);
// Copie des fichiers
rename(_PATH_TESTS_IMAGES_ . 'image_a_supprimerMultiple.png', _PATH_IMAGES_ . 'a/aec65c6b4469bb7267d2d55af5fbd87b');
rename(_PATH_TESTS_IMAGES_ . 'image_a_supprimerMultiple-100x100.png', _PATH_MINIATURES_ . '0/031328c1a7ffe7eed0a2cab4eca05a63');
rename(_PATH_TESTS_IMAGES_ . 'image_a_supprimerMultiple-200x200.png', _PATH_MINIATURES_ . '2/278a70a02e036cc85e0d7e605fdc517f');
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_GET['id'] = '14777777.png';
$_GET['type'] = ressourceObject::typeImage;
/**
* Authentification
*/
$unMembre = new utilisateurObject();
$unMembre->connexion('admin', 'password');
ob_start();
require 'delete.php';
ob_end_clean();
/**
* Désauthentification
*/
$maSession = new sessionObject();
$maSession->deconnexion();
$this->assertEquals(empty($msgErreur), TRUE, "Suppression image ne doit pas être bloqué dans delete.php");
$this->assertEquals(empty($msgWarning), TRUE, "Suppression image ne doit pas être bloqué dans delete.php");
self::setNbMoins(self::fichierImage);
$this->assertEquals(self::countImagesEnBdd(), self::getNb(self::fichierImage), "Suppression image ne doit pas être bloqué en BDD");
self::setNbMoins(self::fichierPossede);
$this->assertEquals(self::countImagesPossedeesEnBdd(), self::getNb(self::fichierPossede), "Suppression possession ne doit pas être bloqué en BDD");
$this->assertEquals(file_exists(_PATH_IMAGES_ . 'a/aec65c6b4469bb7267d2d55af5fbd87b'), FALSE, "Suppression image doit être effacé du HDD");
self::setNbMoins(self::fichierMiniature);
self::setNbMoins(self::fichierMiniature);
$this->assertEquals(self::countMiniaturesEnBdd(), self::getNb(self::fichierMiniature), "Suppression miniatureS ne doit pas être bloqué en BDD");
$this->assertEquals(file_exists(_PATH_MINIATURES_ . '0/031328c1a7ffe7eed0a2cab4eca05a63'), FALSE, "Suppression image doit effacer toutes les miniatures du HDD");
$this->assertEquals(file_exists(_PATH_MINIATURES_ . '2/278a70a02e036cc85e0d7e605fdc517f'), FALSE, "Suppression image doit effacer toutes les miniatures du HDD");
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 B

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -19,22 +19,20 @@
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
*/
namespace ImageHebergTests;
use PHPUnit\Framework\TestCase;
class InstallationTest extends TestCase
{
public function testValidationInstallation(): void
{
class installationTest extends TestCase {
public function testVaidationInstallation() {
/**
* Valeur attendue
*/
$this->expectOutputRegex('#.*L\'installation est OK !$#U');
$this->expectOutputString("L'installation est OK !");
/**
* Exécution du script...
*/
require 'install.php';
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

315
__tests/membreTest.php Normal file
View file

@ -0,0 +1,315 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
use PHPUnit\Framework\TestCase;
class membreTest extends TestCase {
/**
* Fonction requise par l'extension Database
* @return type
*/
public function getConnection() {
$pdo = new PDO('sqlite::memory:');
return $this->createDefaultDBConnection($pdo, ':memory:');
}
/**
* Fonction requise par l'extension Database
* @return \PHPUnit_Extensions_Database_DataSet_DefaultDataSet
*/
public function getDataSet() {
return new PHPUnit_Extensions_Database_DataSet_DefaultDataSet();
}
public function testConnexionMembreExistant() {
// Chargement de la configuration
require_once 'config/config.php';
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['valider'] = 1;
$_POST['userName'] = 'admin';
$_POST['userPassword'] = 'password';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Appel de la page
*/
ob_start();
require 'membre/connexionCompte.php';
ob_end_clean();
/**
* Vérification des valeurs
*/
$maSession = new sessionObject();
$this->assertEquals(utilisateurObject::levelAdmin, $maSession->getLevel(), "connexion : doit être OK");
}
/**
* Création d'un compte membre avec un nom déjà existant
* @depends testConnexionMembreExistant
*/
public function testMembreCreerCompteDoublon() {
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['valider'] = 1;
$_POST['userName'] = 'admin';
$_POST['userPassword'] = 'monPassword';
$_POST['userMail'] = 'myMail@example.com';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Appel de la page
*/
ob_start();
require 'membre/creerCompte.php';
ob_end_clean();
/**
* Vérification des valeurs
*/
$monMembre = new utilisateurObject();
$this->assertEquals(FALSE, $monMembre->connexion($_POST['userName'], $_POST['userPassword']), "connexion : le nom d'utilisateur doit être unique");
}
/**
* Création d'un compte membre.
* @depends testMembreCreerCompteDoublon
*/
public function testMembreCreerCompte() {
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['valider'] = 1;
$_POST['userName'] = 'username';
$_POST['userPassword'] = 'password';
$_POST['userMail'] = 'myMail@example.com';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Appel de la page
*/
ob_start();
require 'membre/creerCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new utilisateurObject(3);
/**
* Vérification des valeurs
*/
// Email
$this->assertEquals('myMail@example.com', $monMembre->getEmail(), "Vérification email");
// ID
$this->assertEquals(3, $monMembre->getId());
// @ IP d'inscription
$this->assertEquals('127.0.0.1', $monMembre->getIpInscription());
// Niveau de droits
$this->assertEquals(utilisateurObject::levelUser, $monMembre->getLevel());
// Nom
$this->assertEquals('username', $monMembre->getUserName());
$this->assertEquals(TRUE, $monMembre->connexion($_POST['userName'], $_POST['userPassword']));
}
/**
* Modification du mail
* @depends testMembreCreerCompte
*/
public function testMembreModifierMail() {
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['modifierMail'] = 1;
$_POST['userPasswordMail'] = 'password';
$_POST['userMail'] = 'john.doe@example.com';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new utilisateurObject();
$this->assertEquals(TRUE, $unMembre->connexion('username', $_POST['userPasswordMail']), "connexion avant");
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération de l'utilisateur
*/
$monMembre = new utilisateurObject(3);
/**
* 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");
}
/**
* Modification du mot de passe
* @depends testMembreModifierMail
*/
public function testMembreModifierPassword() {
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['modifierPwd'] = 1;
$_POST['oldUserPassword'] = 'password';
$_POST['newUserPassword'] = 'monPassword';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new utilisateurObject();
$this->assertEquals(TRUE, $unMembre->connexion('username', $_POST['oldUserPassword']), "connexion avant");
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new utilisateurObject();
/**
* Vérification des valeurs
*/
$this->assertEquals(TRUE, $monMembre->connexion('username', $_POST['newUserPassword']), "connexion");
$this->assertEquals(false, $monMembre->connexion('username', $_POST['oldUserPassword']), "connexion");
}
/**
* Suppression du compte sans cochage de la checkbox
* @depends testMembreModifierPassword
*/
public function testMembreSupprimerCompteRequiertCheckbox() {
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['supprimerCompte'] = 1;
$_POST['userPasswordDelete'] = 'monPassword';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new utilisateurObject();
$this->assertEquals(TRUE, $unMembre->connexion('username', $_POST['userPasswordDelete']), "connexion avant");
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new utilisateurObject();
/**
* Vérification des valeurs
*/
$this->assertEquals(TRUE, $monMembre->connexion('username', $_POST['userPasswordDelete']), "connexion devrait être possible");
}
/**
* Suppression du compte
* @depends testMembreSupprimerCompteRequiertCheckbox
*/
public function testMembreSupprimerCompte() {
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_POST['supprimerCompte'] = 1;
$_POST['userPasswordDelete'] = 'monPassword';
$_POST['confirmeDelete'] = 1;
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Simulation d'une connexion
*/
$unMembre = new utilisateurObject();
$this->assertEquals(TRUE, $unMembre->connexion('username', $_POST['userPasswordDelete']), "connexion avant");
/**
* Appel de la page
*/
ob_start();
require 'membre/monCompte.php';
ob_end_clean();
/**
* Récupération d'un objet
*/
$monMembre = new utilisateurObject();
/**
* Vérification des valeurs
*/
$this->assertEquals(FALSE, $monMembre->connexion('username', $_POST['userPasswordDelete']), "connexion ne devrait plus être possible");
}
/**
* Connexion au compte créé lors de la création de la BDD
* @depends testMembreSupprimerCompte
*/
public function testConnexionCompteHistorique() {
unset($_POST);
/**
* Injection des valeurs du formulaire
*/
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
/**
* Récupération d'un objet
*/
$monMembre = new utilisateurObject();
/**
* Vérification des valeurs
*/
$this->assertEquals(TRUE, $monMembre->connexion('admin', 'password'), "connexion au compte créé à l'import de la BDD devrait être possible");
}
}

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,97 +17,98 @@
* 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';
require _TPL_TOP_;
?>
<h1 class="mb-3"><small>A propos</small></h1>
<h1><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 class="panel panel-default">
<div class="panel-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="//icons.getbootstrap.com/">Bootstrap Icons</a>
<br/>
IA de classification : <a href="//github.com/infinitered/nsfwjs">nsfwjs</a>
<br />
Technologies : PHP, MySQL, HTML5, CSS3
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">Licences</h2>
</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 class="panel-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 GPL V3.
<br />
Graphismes et images : <a href="//getbootstrap.com/">Bootstrap</a>
<br />
Logo "Fork me on GitHub" inspiré de <a href="//github.com/tholman/github-corners">Tim Holman</a>
<br />
Technologies : PHP, MySQL, HTML5, CSS, jQuery
</div>
</div>
<div class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#collapseCNIL">
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">Hébergeur</h2>
</div>
<div class="panel-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="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseCNIL">
Conservations de données à caractère privé
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="collapseCNIL" class="panel-collapse collapse">
<div class="panel-body">
L'utilisation du service peut conduire à l'enregistrement de cookies sur votre ordinateur.
<br />
Vous pouvez supprimer librement ces cookies via les options de votre navigateur internet.
<br />
A défaut, et sauf action spécifique et explicite de votre part, les cookies seront supprimés lors de la fermeture de votre navigateur.
<br /><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.
<br /><br />
Conformément à la directive 2006/24/CE sur la conservation des données, tous les accès au service seront enregistrés et conservés durant <em>- au moins -</em> 2 années.
<br /><br />
Aucune donnée n'est utilisée à but publicitaire ni est transmise à des tiers, ou réutilisée en dehors du présent service.
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#collapseCNIL2">
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseCNIL2">
Responsable du traitement : <?= _ADMINISTRATEUR_NOM_ ?>
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></span>
</a>
</div>
<div id="collapseCNIL2" class="collapse">
<div class="card card-body">
Les informations recueillies font lobjet dun 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>
</h2>
</div>
<div id="collapseCNIL2" class="panel-collapse collapse">
<div class="panel-body">
Les informations recueillies font lobjet dun traitement informatique destiné à personnaliser votre utilisation du service.
<br />
Vous n'&ecirc;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 à <a href="/contact.php"><?= _ADMINISTRATEUR_NOM_ ?> via le formulaire de contact</a>.
<br />
Vous pouvez également, pour des motifs légitimes, vous opposer au traitement des données vous concernant.
</div>
</div>
<?php require _TPL_BOTTOM_ ?>
</div>
<?php require _TPL_BOTTOM_ ?>

133
abuse.php
View file

@ -1,133 +0,0 @@
<?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';
}
// Anti flood
$maSession = new SessionObject();
$msgErreur = '';
require _TPL_TOP_;
// En cas de validation du formulaire
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 - 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($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;
}
}
// Gestion travis
if (!_PHPUNIT_) {
// Je complète le message avec l'IP de mon émeteur
$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']);
$maSession->removeFlag();
}
// Retour utilisateur
echo '<div class="alert alert-success">Votre signalement a été envoyé, merci !</div>';
} else {
// Adresse mail invalide
$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 (!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="<?= $_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_ ?>).
</div>
</div>
<div class="mb-3 form-floating">
<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="<?= $_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"><?= $_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_ ?>

View file

@ -1,59 +0,0 @@
<?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_; ?>

View file

@ -1,180 +0,0 @@
<?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_; ?>

View file

@ -1,73 +0,0 @@
<?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>
&nbsp;Effacer ce<?= $isPlural ?> compte<?= $isPlural ?>
</button>
</form>
</div>
<?php endif; ?>
<?php require _TPL_BOTTOM_; ?>

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,142 +17,147 @@
* 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;
require '../config/config.php';
// Vérification des droits d'accès
UtilisateurObject::checkAccess(UtilisateurObject::LEVEL_ADMIN);
metaObject::checkUserAccess(utilisateurObject::levelAdmin);
require _TPL_TOP_;
?>
<h1 class="mb-3"><small>Nettoyage des incohérences</small></h1>
<h1><small>Nettoyage des incohérences</small></h1>
<?php
$message = '';
// Je récupère la liste des images en BDD
$listeImagesBDD = HelperAdmin::getAllImagesNameBDD();
$listeImagesBDD = metaObject::getAllImagesNameBDD();
// Je récupère la liste des images sur le HDD
$listeImagesHDD = HelperAdmin::getAllImagesNameHDD(_PATH_IMAGES_);
$listeImagesHDD = metaObject::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 = HelperAdmin::getAllMiniaturesNameBDD();
$listeMiniaturesBDD = metaObject::getAllMiniaturesNameBDD();
// Je récupère la liste des miniatures en HDD
$listeMiniaturesHDD = HelperAdmin::getAllImagesNameHDD(_PATH_MINIATURES_);
$listeMiniaturesHDD = metaObject::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) {
$message .= '<br />Suppression de la BDD de l\'image ' . $value;
// Images uniquement en BDD
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, RessourceObject::SEARCH_BY_MD5);
$monImage->supprimer();
}
// Images uniquement en HDD
foreach ((array)$listeErreursImagesHDD as $value) {
$message .= '<br />Suppression du disque de l\'image ' . $value;
// Je crée mon objet et lance la suppression
$monImage = new imageObject($value);
$monImage->supprimer();
}
// Images uniquement en HDD
foreach ((array) $listeErreursImagesHDD as $value) {
$message .= '<br />Suppression du disque de l\'image ' . $value;
// Suppression du fichier
$rep = substr($value, 0, 1) . '/';
$pathFinal = _PATH_IMAGES_ . $rep . $value;
unlink($pathFinal);
}
// Miniatures uniquement en BDD
foreach ((array)$listeErreursMiniaturesBDD as $value) {
$message .= '<br />Suppression de la BDD de la miniature ' . $value;
// Suppression du fichier
$rep = substr($value, 0, 1) . '/';
$pathFinal = _PATH_IMAGES_ . $rep . $value;
unlink($pathFinal);
}
// Miniatures uniquement en BDD
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, RessourceObject::SEARCH_BY_MD5);
$maMiniature->supprimer();
}
// Je crée mon objet et lance la suppression
$maMiniature = new miniatureObject($value);
$maMiniature->supprimer();
}
// Miniatures uniquement en HDD
foreach ((array)$listeErreursMiniaturesHDD as $value) {
$message .= '<br />Suppression du disque de la miniature ' . $value;
// Miniatures uniquement en HDD
foreach ((array) $listeErreursMiniaturesHDD as $value) {
$message .= '<br />Suppression du disque de la miniature ' . $value;
// Suppression du fichier
$rep = substr($value, 0, 1) . '/';
$pathFinal = _PATH_MINIATURES_ . $rep . $value;
unlink($pathFinal);
}
$message .= '<br />Effacement terminé !';
?>
// Suppression du fichier
$rep = substr($value, 0, 1) . '/';
$pathFinal = _PATH_MINIATURES_ . $rep . $value;
unlink($pathFinal);
}
$message .= '<br />Effacement terminé !';
?>
<div class="alert alert-success">
<?= $message ?>
</div>
<?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
</div>
<div class="card-body">
<ul>
<?php foreach ((array)$listeErreursImagesBDD as $value) : ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
<?= $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) : ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
<?= $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) : ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
<?= $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) : ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<form method="post">
<button class="btn btn-danger" type="submit" name="effacer">
<span class="bi-trash"></span>
&nbsp;Supprimer les incohérences
</button>
</form>
<?php endif; ?>
<?php require _TPL_BOTTOM_; ?>
<div class="alert alert-success">
<?= $message ?>
</div>
<?php else: ?>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<?= $listeErreursImagesBDD->count() ?> image(s) présente(s) uniquement en BDD
</h2>
</div>
<div class="panel-body">
<ul>
<?php foreach ((array) $listeErreursImagesBDD as $value): ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<?= $listeErreursImagesHDD->count() ?> image(s) présente(s) uniquement sur HDD
</h2>
</div>
<div class="panel-body">
<ul>
<?php foreach ((array) $listeErreursImagesHDD as $value): ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<?= $listeErreursMiniaturesBDD->count() ?> miniature(s) présente(s) uniquement en BDD
</h2>
</div>
<div class="panel-body">
<ul>
<?php foreach ((array) $listeErreursMiniaturesBDD as $value): ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<?= $listeErreursMiniaturesHDD->count() ?> miniature(s) présente(s) uniquement sur HDD
</h2>
</div>
<div class="panel-body">
<ul>
<?php foreach ((array) $listeErreursMiniaturesHDD as $value): ?>
<li><?= $value ?> (<strong>A effacer manuellement</strong>)</li>
<?php endforeach; ?>
</ul>
</div>
</div>
<form method="post">
<button class="btn btn-danger" type="submit" name="effacer">
<span class="glyphicon glyphicon-trash"></span>
&nbsp;
Effacer ces fichiers
</button>
</form>
<?php
endif;
require _TPL_BOTTOM_;
?>

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,58 +17,56 @@
* 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);
metaObject::checkUserAccess(utilisateurObject::levelAdmin);
require _TPL_TOP_;
?>
<h1 class="mb-3"><small>Nettoyage des fichiers jamais utilisés</small></h1>
<h1><small>Nettoyage des fichiers jamais utilisés</small></h1>
<?php
$message = '';
// Je récupère la liste des images jamais affichées
$listeImages = HelperAdmin::getNeverUsedFiles();
$isPlural = ($listeImages->count() > 1 ? 's' : '');
$listeImages = metaObject::getNeverUsedFiles();
// Si l'effacement est demandé
if (isset($_POST['effacer'])) :
$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">
<?= $message ?>
</div>
<?php else : ?>
<div class="card">
<div class="card-header">
<?= $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>
<a href="<?= str_replace('http:', 'https:', _URL_IMAGES_) . $value ?>?forceDisplay=1" target="_blank"><?= $value ?></a>
</li>
<?php endforeach; ?>
</ul>
foreach ((array) $listeImages as $value) {
$message .= '<br />Suppression de l\'image ' . $value;
</div>
<form method="post">
<button class="btn btn-danger" type="submit" name="effacer">
<span class="bi-trash"></span>
&nbsp;Effacer ce<?= $isPlural ?> fichier<?= $isPlural ?>
</button>
</form>
</div>
<?php endif; ?>
<?php require _TPL_BOTTOM_; ?>
// Je crée mon objet et lance la suppression
$monImage = new imageObject($value);
$monImage->supprimer();
}
$message .= '<br />Effacement terminé !';
?>
<div class = "alert alert-success">
<?= $message ?>
</div>
<?php else: ?>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<?= $listeImages->count() ?> image(s) envoyée(s) il y a au moins <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?> jour(s) et jamais affichée(s)
</h2>
</div>
<div class="panel-body">
<ul>
<?php foreach ((array) $listeImages as $value): ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
<form method="post">
<button class="btn btn-danger" type="submit" name="effacer">
<span class="glyphicon glyphicon-trash"></span>
&nbsp;
Effacer ces fichiers
</button>
</form>
</div>
<?php
endif;
require _TPL_BOTTOM_;
?>

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,58 +17,56 @@
* 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);
metaObject::checkUserAccess(utilisateurObject::levelAdmin);
require _TPL_TOP_;
?>
<h1 class="mb-3"><small>Nettoyage des fichiers dormants</small></h1>
<h1><small>Nettoyage des fichiers dormants</small></h1>
<?php
$message = '';
// Je récupère la liste des images non affichées depuis xx jours
$listeImages = HelperAdmin::getUnusedFiles();
$isPlural = ($listeImages->count() > 1 ? 's' : '');
$listeImages = metaObject::getUnusedFiles();
// Si l'effacement est demandé
if (isset($_POST['effacer'])) :
$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">
<?= $message ?>
</div>
<?php else : ?>
<div class="card">
<div class="card-header">
<?= $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>
<a href="<?= str_replace('http:', 'https:', _URL_IMAGES_) . $value ?>?forceDisplay=1" target="_blank"><?= $value ?></a>
</li>
<?php endforeach; ?>
</ul>
foreach ((array) $listeImages as $value) {
$message .= '<br />Suppression de l\'image ' . $value;
</div>
<form method="post">
<button class="btn btn-danger" type="submit" name="effacer">
<span class="bi-trash"></span>
&nbsp;Effacer ce<?= $isPlural ?> fichier<?= $isPlural ?>
</button>
</form>
</div>
<?php endif; ?>
<?php require _TPL_BOTTOM_; ?>
// Je crée mon objet et lance la suppression
$monImage = new imageObject($value);
$monImage->supprimer();
}
$message .= '<br />Effacement terminé !';
?>
<div class="alert alert-success">
<?= $message ?>
</div>
<?php else: ?>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<?= $listeImages->count() ?> image(s) non affichée(s) depuis au moins <?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jour(s).
</h2>
</div>
<div class="panel-body">
<ul>
<?php foreach ((array) $listeImages as $value): ?>
<li><?= $value ?></li>
<?php endforeach; ?>
</ul>
</div>
<form method="post">
<button class="btn btn-danger" type="submit" name="effacer">
<span class="glyphicon glyphicon-trash"></span>
&nbsp;
Effacer ces fichiers
</button>
</form>
</div>
<?php
endif;
require _TPL_BOTTOM_;
?>

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,85 +17,45 @@
* 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);
metaObject::checkUserAccess(utilisateurObject::levelAdmin);
require _TPL_TOP_;
?>
<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>
&nbsp;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>
&nbsp;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>
&nbsp;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>
&nbsp;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>
&nbsp;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>
&nbsp;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>
&nbsp;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>
&nbsp;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>
<h1><small>Panneau d'administration</small></h1>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
Outils
</h2>
</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="bi-list-check"></span>
&nbsp;
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>
&nbsp;
Vérifier la cohérence disque et BDD
</a>
</div>
<div class="panel-body">
<a href="<?= _URL_ADMIN_ ?>listeFichiers.php" class="btn btn-default">
<span class="glyphicon glyphicon-list-alt"></span>
&nbsp;
Lister les fichiers présents sur le disque
</a>
<div class="clearfix"></div>
<br />
<a href="<?= _URL_ADMIN_ ?>cleanFilesNeverUsed.php" class="btn btn-danger">
<span class="glyphicon glyphicon-trash"></span>
&nbsp;
Fichiers jamais utilisés
</a>
<div class="clearfix"></div>
<br />
<a href="<?= _URL_ADMIN_ ?>cleanInactiveFiles.php" class="btn btn-danger">
<span class="glyphicon glyphicon-flash"></span>
&nbsp;
Fichiers inactifs
</a>
<div class="clearfix"></div>
<br />
<a href="<?= _URL_ADMIN_ ?>cleanErrors.php" class="btn btn-warning">
<span class="glyphicon glyphicon-check"></span>
&nbsp;
Vérifier la cohérence disque / BDD
</a>
</div>
<?php require _TPL_BOTTOM_ ?>
</div>
<?php require _TPL_BOTTOM_ ?>

View file

@ -1,134 +0,0 @@
<?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_; ?>

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,44 +17,40 @@
* 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);
metaObject::checkUserAccess(utilisateurObject::levelAdmin);
require _TPL_TOP_;
?>
<h1 class="mb-3"><small>Images présentes sur le disque</small></h1>
<ul>
<?php
<h1><small>Images présentes sur le disque</small></h1>
<ul>
<?php
/**
* Scan récursif
* @param string $path
* @return string
*/
function getScandirRecursif(string $path): string
{
$monRetour = '<ul>';
/**
* Scan récursif
* @param string $path
* @return string
*/
function getScandirRecursif($path) {
$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 . '/');
}
}
}
$monRetour .= '</ul>';
return $monRetour;
}
// 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;
}
echo getScandirRecursif(_PATH_IMAGES_);
?>
</ul>
<?php require _TPL_BOTTOM_ ?>
echo getScandirRecursif(_PATH_IMAGES_);
?>
</ul>
<?php require _TPL_BOTTOM_ ?>

View file

@ -1,139 +0,0 @@
<?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_; ?>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,83 +0,0 @@
<?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>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">
<div class="card-header">
MySQL
</div>
<div class="card-body">
<?= HelperSysteme::getMysqlVersion() ?>
</div>
</div>
<div class="card">
<div class="card-header">
Imagick
</div>
<div class="card-body">
<?= HelperSysteme::getImagickVersion() ?>
</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 : <?= 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 class="card">
<div class="card-header">
Droits sur tous les dossiers dans files/
</div>
<div class="card-body">
<ul>
<?php
$lesDroits = HelperSysteme::isRecursivelyWritable(_PATH_IMAGES_);
foreach ((array)$lesDroits as $unItem) :
?>
<li><?= $unItem ?></li>
<?php endforeach; ?>
</ul>
</div>
</div>
<?php require _TPL_BOTTOM_; ?>

115
cgu.php
View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,82 +17,52 @@
* 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';
require _TPL_TOP_;
?>
<h1 class="mb-3"><small>Conditions Générales d'Utilisation de <?= _SITE_NAME_ ?></small></h1>
<h1><small>Conditions Générales d'Utilisation</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&eacute;avis, et &agrave; tout moment.</div>
<div class="card">
<div class="card-header">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">
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>
</h3>
</div>
<div class="panel-body">
<ul>
<li>Toutes images de type JPG, PNG, GIF.</li>
<li>Contenu conforme &agrave; la l&eacute;gislation fran&ccedil;aise.</li>
<li>Pornographie et &eacute;rotisme non autoris&eacute;s.</li>
</ul>
</div>
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">
Propri&eacute;t&eacute;s de l'h&eacute;bergement
</h3>
</div>
<div class="panel-body">
<ul>
<li>Gratuit.</li>
<li>Traffic illimit&eacute; <em>(hors abus)</em>.</li>
<li><b>Conservation :</b>
<ul>
<li><?= _DELAI_INACTIVITE_AVANT_EFFACEMENT_IMAGES_ ?> jour(s) à compter de la dernière utilisation du fichier.</li>
<li>A défaut, <?= _DELAI_EFFACEMENT_IMAGES_JAMAIS_AFFICHEES_ ?> jour(s) après l'envoi <em>(si aucun affichage)</em>.</li>
</ul>
</li>
<li>Nombre d'images par compte : illimit&eacute;.</li>
<li>Les fichiers restent votre propri&eacute;t&eacute;.</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&eacute;es poss&eacute;d&eacute;es seront fournies en cas de demande judiciaire.</li>
<li>Rappel : l'administrateur peut-avoir acc&egrave;s &agrave; toutes les donn&eacute;es du service.</li>
</ul>
<div class="panel-footer">
<em>Mise &agrave; jour le 29 juin 2018 : réduction des durées de conservation des images inactives</em>
</div>
</div>
<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_ ?>
</div>
<?php require _TPL_BOTTOM_ ?>

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -18,338 +17,264 @@
* 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';
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="#v2x">
v2.x - A venir
&nbsp;<span class="bi-caret-down-fill"></span>
<h1><small>Historique des versions</small></h1>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v21">
v2.1 - en cours
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v21" class="panel-collapse">
<div class="panel-body">
<ul>
<li>Migration bootstrap 3 => 4</li>
<li>Sélection uniquement des images lors du choix du fichier sur l'ordinateur</li>
<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>
</div>
</div>
<div class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v25">
v2.5 - Janvier 2024
&nbsp;<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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v24">
v2.4 - Décembre 2023
&nbsp;<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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v23">
v2.3 - Août 2023
&nbsp;<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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v22">
v2.2 - Décembre 2021
&nbsp;<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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v21">
v2.1 - Février 2021
&nbsp;<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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v205">
v2.0.5 - 2020
&nbsp;<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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v204">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v204">
v2.0.4 - Octobre 2019
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v204" class="panel-collapse">
<div class="panel-body">
<ul>
<li>Améliorations techniques de l'outil pour les maintenances futures</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v203">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v203">
v2.0.3 - Octobre 2019
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v203" class="panel-collapse collapse">
<div class="panel-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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v202">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v202">
v2.0.2 - Janvier 2019
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v202" class="panel-collapse collapse">
<div class="panel-body">
<ul>
<li>Correction d'une erreur les images dont seulement les miniatures étaient affichées pouvaient être supprimées.</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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v201">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v201">
v2.0.1 - Juin 2018
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v201" class="panel-collapse collapse">
<div class="panel-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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v20">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v20">
v2.0 - Novembre 2016
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v20" class="panel-collapse collapse">
<div class="panel-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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v19">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v19">
v1.9 - Janvier 2014
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v19" class="panel-collapse collapse">
<div class="panel-body">
<ul>
<li>Passage à la programation objet</li>
<li>Reprise, factorisation et optimisation globale du site</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v127">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v127">
v1.2.7 - 26 avril 2012
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v127" class="panel-collapse collapse">
<div class="panel-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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v126">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v126">
v1.2.6 - 9 janvier 2012
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v126" class="panel-collapse collapse">
<div class="panel-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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v125">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v125">
v1.2.5 - 30 octobre 2011
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v125" class="panel-collapse collapse">
<div class="panel-body">
<ul>
<li>Suppression de la limite des dimensions d'images pour les utilisateurs enregistrés</li>
<li>Ajout d'une fonction permettant le blocage d'images précises + affichage d'une image d'information sur le blocage</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v124">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v124">
v1.2.4 - 08 septembre 2011
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v124" class="panel-collapse collapse">
<div class="panel-body">
<ul>
<li>Meilleure gestion des images inexistantes (erreurs 404)</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v123e">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v123e">
v1.2.3.e - 14 août 2011
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v123e" class="panel-collapse collapse">
<div class="panel-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 class="card">
<div class="card-header">
<a data-bs-toggle="collapse" href="#v123d">
</div>
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#v123d">
v1.2.3.d - 10 août 2011
&nbsp;<span class="bi-caret-down-fill"></span>
&nbsp;<span class="caret"></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>
</h2>
</div>
<div id="v123d" class="panel-collapse collapse">
<div class="panel-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>
<?php require _TPL_BOTTOM_ ?>
</div>
<?php require _TPL_BOTTOM_ ?>

View file

@ -1,54 +0,0 @@
<?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);
}
}

View file

@ -1,404 +0,0 @@
<?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;
}
}

View file

@ -1,214 +0,0 @@
<?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;
}
}

View file

@ -1,170 +0,0 @@
<?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 . '">&nbsp;' . $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">&nbsp;' . $folder . '</span>');
} else {
$monRetour->append('<span class="bi-exclamation-circle text-danger">&nbsp;' . $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));
}
}

View file

@ -1,47 +0,0 @@
<?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 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;
}
}

View file

@ -1,375 +0,0 @@
<?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;
use ImagickException;
use PDO;
/**
* Les images
*/
class ImageObject extends RessourceObject implements RessourceInterface
{
/**
* Constructeur
* @param string $value Identifiant image-heberg
* @param string $fromField Champ à utiliser en BDD
* @throws ImageHebergException
*/
public function __construct(string $value = '', string $fromField = RessourceObject::SEARCH_BY_NAME)
{
// Définition du type pour le RessourceObject
$this->setType(RessourceObject::TYPE_IMAGE);
// 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 . ')');
}
}
public function charger(string $value, string $fromField = RessourceObject::SEARCH_BY_NAME): bool
{
// Charger les informations depuis la BDD
$this->chargerFromBdd([$value], $fromField);
// Gestion du retour
return ($this->getId() !== 0);
}
/**
* 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 = [];
if (count($values) > 0) {
$monRetour = (new ImageObject())->chargerFromBdd((array)$values, $fromField, false, $orderByIdAsc);
}
return $monRetour;
}
/**
* 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
*/
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 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());
$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());
$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();
}
/**
* 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 getMiniatures(bool $onlyPreview = false): ArrayObject
{
$monRetour = new ArrayObject();
// Chargement des miniatures
$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) {
// Nom du fichier
$monRetour->append($value->new_name);
}
return $monRetour;
}
/**
* @throws ImageHebergException
*/
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;
/**
* Détermination du nom &&
* Vérification de sa disponibilité
*/
$tmpImage = new ImageObject();
$nb = 0;
do {
// Récupération d'un nouveau nom
$new_name = $this->genererNom($nb);
// Incrémentation compteur entropie sur le nom
$nb++;
} while ($tmpImage->charger($new_name) !== false);
// Effacement de l'objet temporaire
unset($tmpImage);
// 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->getNbUsages() === 0) {
// Copie du fichier vers l'emplacement de stockage
// 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
if ($monRetour) {
/**
* Informations sur l'image
*/
// Dimensions
$imageInfo = getimagesize($this->getPathMd5());
$this->setLargeur($imageInfo[0]);
$this->setHauteur($imageInfo[1]);
// Poids
$this->setPoids(filesize($this->getPathMd5()));
// Nom originel (non récupérable sur le fichier)
$this->setNomOriginal($this->getNomTemp());
// @ IP d'envoi
$this->setIpEnvoi($_SERVER['REMOTE_ADDR']);
/**
* Création en BDD
*/
$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());
$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());
$req->bindValue(':isBloquee', $this->isBloquee());
if (!$req->execute()) {
// Gestion de l'erreur d'insertion en BDD
$monRetour = false;
} else {
/**
* Récupération de l'ID de l'image
*/
$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;
}
}
return $monRetour;
}
}

View file

@ -1,108 +0,0 @@
<?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 PDO;
use PDOStatement;
/**
* Lien vers la BDD
*
* @author anael
*/
class MaBDD
{
// PDO
private PDO $maBDD;
// Instance de la classe
private static ?MaBDD $monInstance = null;
/**
* Constructeur
*/
private function __construct()
{
$this->maBDD = new PDO('mysql:host=' . _BDD_HOST_ . ';dbname=' . _BDD_NAME_, _BDD_USER_, _BDD_PASS_);
$this->maBDD->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->maBDD->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
/**
* Crée & renvoi l'objet d'instance
* @return MaBDD
*/
public static function getInstance(): MaBDD
{
// Si pas de connexion active, en crée une
if (is_null(self::$monInstance)) {
self::$monInstance = new MaBDD();
}
return self::$monInstance;
}
/**
* PDO::query
* @param string $query
* @return false|PDOStatement
*/
public function query(string $query): bool|PDOStatement
{
return $this->maBDD->query($query);
}
/**
* PDO::prepare
* @param string $query
* @return false|PDOStatement
*/
public function prepare(string $query): bool|PDOStatement
{
return $this->maBDD->prepare($query);
}
/**
* PDO::lastInsertId
* @return string
*/
public function lastInsertId(): string
{
return $this->maBDD->lastInsertId();
}
/**
* Fermeture du PDO
*/
public static function close(): void
{
self::$monInstance = null;
}
/**
* PDO::getAttribute
* @param int $attribute
* @return mixed
*/
public function getAttribute(int $attribute): mixed
{
return $this->maBDD->getAttribute($attribute);
}
}

View file

@ -1,243 +0,0 @@
<?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;
use PDO;
/**
* Les miniatures
*/
class MiniatureObject extends RessourceObject implements RessourceInterface
{
private int $idImage;
private bool $isPreview = false;
/**
* Constructeur
* @param string $value Identifiant image-heberg
* @param string $fromField Champ à utiliser en BDD
* @throws ImageHebergException
*/
public function __construct(string $value = '', string $fromField = RessourceObject::SEARCH_BY_NAME)
{
// Définition du type pour le RessourceObject
$this->setType(RessourceObject::TYPE_MINIATURE);
// 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);
}
}
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 ' . $fromField . ' = :value');
$req->bindValue(':value', $value);
$req->execute();
// J'éclate les informations
$resultat = $req->fetch();
if ($resultat !== false) {
$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->setId($resultat->id);
$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
$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;
}
return $monRetour;
}
public function sauver(): void
{
// J'enregistre les infos en BDD
$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(':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);
$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());
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
$req->execute();
}
public function supprimer(): void
{
/**
* Suppression de l'image en BDD
*/
// Suppresion de l'image en BDD
$req = MaBDD::getInstance()->prepare('DELETE FROM thumbnails 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
&& file_exists($this->getPathMd5())
) {
unlink($this->getPathMd5());
}
}
/**
* @throws Exception
*/
public function creer(): bool
{
// Retour
$monRetour = true;
/**
* Détermination du nom &&
* Vérification de sa disponibilité
*/
$tmpMiniature = new MiniatureObject();
$nb = 0;
do {
// Récupération d'un nouveau nom
$new_name = $this->genererNom($nb);
// Incrémentation compteur entropie sur le nom
$nb++;
} while ($tmpMiniature->charger($new_name) !== false);
// Effacement de l'objet temporaire
unset($tmpMiniature);
// On enregistre le nom
$this->setNomNouveau($new_name);
/**
* Déplacement du fichier
*/
// Vérification de la non existence du fichier
if ($this->getNbUsages() === 0) {
$monRetour = rename($this->getPathTemp(), $this->getPathMd5());
}
// Ssi copie du fichier réussie
if ($monRetour) {
/**
* Informations sur l'image
*/
// Dimensions
$imageInfo = getimagesize($this->getPathMd5());
$this->setLargeur($imageInfo[0]);
$this->setHauteur($imageInfo[1]);
// Poids
$this->setPoids(filesize($this->getPathMd5()));
/**
* Création en BDD
*/
$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());
$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());
if (!$req->execute()) {
// Gestion de l'erreur d'insertion en BDD
$monRetour = false;
} else {
/**
* Récupération de l'ID de l'image
*/
$idEnregistrement = MaBDD::getInstance()->lastInsertId();
$this->setId($idEnregistrement);
}
}
return $monRetour;
}
/**
* GETTERS & SETTERS
*/
/**
* ID image parente
* @return int
*/
public function getIdImage(): int
{
return $this->idImage;
}
/**
* ID image parente
* @param int $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;
}
}

View file

@ -1,735 +0,0 @@
<?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;
use ImagickException;
use PDO;
/**
* Fonctions génériques aux images et miniatures
*/
abstract class RessourceObject
{
// Types de ressources
final public const int TYPE_IMAGE = 1;
final public const int TYPE_MINIATURE = 2;
// 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(int $nb = 0): string
{
// Random pour unicité + cassage lien nom <-> @IP
$random = random_int(100, 999);
// @IP expéditeur
$adresseIP = abs(crc32($_SERVER['REMOTE_ADDR'] . $random));
// Timestamp d'envoi
$timestamp = $_SERVER['REQUEST_TIME'];
// 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
// 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(): string
{
// Création d'une image => Utilisation du fichier temporaire
if (is_null($this->md5) && $this->getPathTemp()) {
// Fichier temporaire...
$this->md5 = md5_file($this->getPathTemp());
}
return $this->md5;
}
/**
* Path sur le HDD
* @return string
*/
public function getPathMd5(): string
{
// Path du type d'image
if ($this->getType() === self::TYPE_IMAGE) {
// Image
$pathDuType = _PATH_IMAGES_;
} else {
// Miniature
$pathDuType = _PATH_MINIATURES_;
}
// Path final
if ($this->getType() === self::TYPE_IMAGE && ($this->getId() === 1 || $this->getId() === 2)) {
// Gestion des images spécifiques 404 / ban
$pathFinal = $pathDuType . $this->getNomNouveau();
} else {
// Cas par défaut
$rep = substr($this->getMd5(), 0, 1) . '/';
$pathFinal = $pathDuType . $rep . $this->getMd5();
}
return $pathFinal;
}
/**
* Nombre d'images ayant le même MD5 (Normalement 1 à minima, l'image courante...)
* @return int nombre d'images ayant ce MD5 (0 par défaut)
*/
public function getNbUsages(): int
{
$monRetour = 0;
// 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(bool $forceHttps = false): string
{
// Path du type d'image
if ($this->getType() === self::TYPE_IMAGE) {
// Image
$urlDuType = _URL_IMAGES_;
} else {
// Miniature
$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 horaire
* @param string $pathSrc chemin de la ressource d'origine
* @param string $pathDst chemin de la ressource de destination
* @return bool succès ?
* @throws ImagickException
*/
public function rotation(int $angle, string $pathSrc, string $pathDst): bool
{
// Je charge l'image en mémoire
$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'enregistre l'image
return HelperImage::setImage($resImg, HelperImage::getType($pathSrc), $pathDst);
}
/**
* Redimensionne une image en respectant le ratio de l'image original
* @param string $pathSrc chemin de la ressource d'origine
* @param string $pathDst chemin de la ressource de destination
* @param int $largeurDemandee largeur souhaitée
* @param int $hauteurDemandee hauteur souhaitée
* @return bool réussi ?
* @throws ImagickException
*/
public function redimensionner(string $pathSrc, string $pathDst, int $largeurDemandee, int $hauteurDemandee): bool
{
// Chargement de l'image
$monImage = HelperImage::getImage($pathSrc);
// Récupération de ses dimensions
$largeurImage = $monImage->getImageWidth();
$hauteurImage = $monImage->getImageHeight();
// Dimensions incohérentes : on arrête
if ($hauteurImage <= 0 || $hauteurDemandee <= 0 || $largeurImage <= 0 || $largeurDemandee <= 0 || $largeurImage <= $largeurDemandee || $hauteurImage <= $hauteurDemandee) {
return false;
}
// 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 {
// Cas standard (image non animée)
$monImage->thumbnailImage($largeurDemandee, $hauteurDemandee, true);
}
// Ecriture de l'image
return HelperImage::setImage($monImage, HelperImage::getType($pathSrc), $pathDst);
}
/**
* Cet utilisateur est-il propriétaire de l'image ?
* @return bool
*/
public function isProprietaire(): bool
{
$monRetour = false;
// Si l'image à un propriétaire...
if ($this->getIdProprietaire() !== null) {
// Le propriétaire est-il connecté ?
$uneSession = new SessionObject();
// Est-ce le propriétaire de l'image ?
if ($this->getIdProprietaire() === $uneSession->getId()) {
// Si oui... on confirme !
$monRetour = true;
}
}
return $monRetour;
}
/**
* Date d'envoi formatée
* @return string
*/
public function getDateEnvoiFormatee(): string
{
$phpdate = strtotime($this->getDateEnvoiBrute());
return date('d/m/Y H:i:s', $phpdate);
}
/**
* Date de dernier affichage formaté
* @return string
*/
public function getLastViewFormate(): string
{
$monRetour = '?';
if ($this->getLastView() !== '0000-00-00') {
$phpdate = strtotime($this->getLastView());
// Gestion du cas de non affichage
if ($phpdate !== 0 && $phpdate !== false) {
$monRetour = date('d/m/Y', $phpdate);
}
}
return $monRetour;
}
/**
* Nombre d'appels IPv4 & IPv6
* @return int
*/
public function getNbViewTotal(): int
{
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(): string
{
return htmlentities($this->nomOriginal, ENT_SUBSTITUTE);
}
/**
* Met à jour les statistiques (nb d'affichage et date) en BDD
*/
public function updateStatsAffichage(string $remoteAddr): void
{
// 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();
}
/**
* GETTERS ET SETTERS
*/
/**
* ID de la ressource
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* Nom original de la ressource
* @return string
*/
protected function getNomOriginal(): string
{
return $this->nomOriginal;
}
/**
* Nom image-heberg
* @return string
*/
public function getNomNouveau(): string
{
return $this->nomNouveau;
}
/**
* Largeur en px
* @return int
*/
public function getLargeur(): int
{
return $this->largeur;
}
/**
* Hauteur en px
* @return int
*/
public function getHauteur(): int
{
return $this->hauteur;
}
/**
* Poids de la ressource
* @return int
*/
public function getPoids(): int
{
return $this->poids;
}
/**
* Poids de la ressource en Mo
* @return float
*/
public function getPoidsMo(): float
{
return round($this->getPoids() / 1024 / 1024, 1);
}
/**
* Date de dernier affichage
* @return string
*/
protected function getLastView(): string
{
return $this->lastView;
}
/**
* Nb d'affichage en IPv4
* @return int
*/
protected function getNbViewIPv4(): int
{
return $this->nbViewIPv4;
}
/**
* Nb d'affichage en IPv6
* @return int
*/
protected function getNbViewIPv6(): int
{
return $this->nbViewIPv6;
}
/**
* Date d'envoi du fichier
* @return string
*/
public function getDateEnvoiBrute(): string
{
return $this->dateEnvoi;
}
/**
* @ IP d'envoi
* @return string
*/
public function getIpEnvoi(): string
{
return $this->ipEnvoi;
}
/**
* Image bloquée ?
* @return bool
*/
public function isBloquee(): bool
{
return $this->isBloquee;
}
/**
* Image signalée ?
* @return bool
*/
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(): string
{
return $this->pathTemp;
}
/**
* Type d'image
* @return int ressourceObject const
*/
public function getType(): int
{
return $this->type;
}
/**
* Nom temporaire (PC utilisateur - upload d'image)
* @return string
*/
public function getNomTemp(): string
{
return $this->nomTemp;
}
/**
* Nom temporaire (PC utilisateur - upload d'image)
* @param string $nomTemp
*/
public function setNomTemp(string $nomTemp): void
{
$this->nomTemp = $nomTemp;
}
/**
* Type d'image
* @param int $type RessourceObject const
*/
public function setType(int $type): void
{
$this->type = $type;
}
/**
* Path temporaire (upload d'image)
* @param string $pathTemp
*/
public function setPathTemp(string $pathTemp): void
{
$this->pathTemp = $pathTemp;
}
/**
* Image bloquée ?
* @param bool $bloquee
*/
public function setBloquee(bool $bloquee): void
{
$this->isBloquee = $bloquee;
}
/**
* Image signalée ?
* @param bool $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(int $id): void
{
$this->id = $id;
}
/**
* Nom original de la ressource
* @param string $nomOriginal
*/
protected function setNomOriginal(string $nomOriginal): void
{
$this->nomOriginal = $nomOriginal;
}
/**
* Nom image-heberg
* @param string $nomNouveau
*/
protected function setNomNouveau(string $nomNouveau): void
{
$this->nomNouveau = $nomNouveau;
}
/**
* Largeur en px
* @param int $largeur
*/
protected function setLargeur(int $largeur): void
{
$this->largeur = $largeur;
}
/**
* Hauteur en px
* @param int $hauteur
*/
protected function setHauteur(int $hauteur): void
{
$this->hauteur = $hauteur;
}
/**
* Poids de la ressource
* @param int $poids
*/
protected function setPoids(int $poids): void
{
$this->poids = $poids;
}
/**
* Date de dernier affichage
* @param ?string $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;
}
/**
* Nb d'affichage en IPv4
* @param int $nbViewIPv4
*/
protected function setNbViewIPv4(int $nbViewIPv4): void
{
$this->nbViewIPv4 = $nbViewIPv4;
}
/**
* Nb d'affichage en IPv6
* @param int $nbViewIPv6
*/
protected function setNbViewIPv6(int $nbViewIPv6): void
{
$this->nbViewIPv6 = $nbViewIPv6;
}
/**
* Date d'envoi du fichier
* @param string $dateEnvoi
*/
protected function setDateEnvoi(string $dateEnvoi): void
{
$this->dateEnvoi = $dateEnvoi;
}
/**
* MD5 de la ressource
* @param string $md5
*/
protected function setMd5(string $md5): void
{
$this->md5 = $md5;
}
/**
* @ IP d'envoi
* @param string $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;
}
}

View file

@ -1,173 +0,0 @@
<?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;
/**
* Gestion des sessions
*/
class SessionObject
{
// @ IP de l'utilisateur
private string $IP = '';
// Objet utilisateur
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 (!_PHPUNIT_ && session_status() === PHP_SESSION_NONE) {
// Je lance la session côté PHP
session_start();
}
// 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']);
}
}
/**
* Mon utilisateur
* @return UtilisateurObject
*/
private function getUserObject(): UtilisateurObject
{
return $this->userObject ?? new UtilisateurObject();
}
/**
* Mon utilisateur
* @param UtilisateurObject $userObject Objet utilisateur
*/
public function setUserObject(UtilisateurObject $userObject): void
{
$this->userObject = $userObject;
$_SESSION['userObject'] = $userObject;
}
/**
* Nom d'utilisateur
* @return string
*/
public function getUserName(): string
{
return $this->getUserObject()->getUserName();
}
/**
* @ IP
* @return string
*/
public function getIP(): string
{
return $this->IP;
}
/**
* Niveau de droits
* @return int
*/
public function getLevel(): int
{
return $this->getUserObject()->getLevel();
}
/**
* ID en BDD
* @return int
*/
public function getId(): int
{
return $this->getUserObject()->getId();
}
/**
* IP
* @param string $IP
*/
public function setIP(string $IP): void
{
$this->IP = $IP;
// On enregistre dans la session
$_SESSION['IP'] = $this->getIP();
}
/**
* Vérification des droits de l'utilisateur pour la page
* @param int $levelRequis
* @return bool
*/
public function verifierDroits(int $levelRequis): bool
{
$monRetour = false;
if ($this->getLevel() >= $levelRequis) {
$monRetour = true;
}
return $monRetour;
}
/**
* Déconnexion d'un utilisateur
*/
public function deconnexion(): void
{
// Destruction de l'objet utilisateur
unset($_SESSION['userObject']);
if (!_PHPUNIT_) {
// Je détruis la session
session_destroy();
}
}
/**
* Active le flag de suivi (vérification d'affichage de page avant envoi)
*/
public function setFlag(): void
{
$_SESSION['flag'] = time();
}
/**
* Supprime le flag de suivi
*/
public function removeFlag(): void
{
unset($_SESSION['flag']);
}
/**
* Vérifie le flag de suivi (a été activé il y a plus d'une seconde)
* @return bool Suivi OK ?
*/
public function checkFlag(): bool
{
$monRetour = false;
// Au moins une seconde pour remplir le formulaire
if (isset($_SESSION['flag']) && (time() - $_SESSION['flag']) > 1) {
$monRetour = true;
}
return $monRetour;
}
}

View file

@ -1,182 +0,0 @@
<?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;
}
}

View file

@ -1,550 +0,0 @@
<?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 PDO;
use ArrayObject;
/**
* Gestion (BDD) des utilisateurs
*/
class UtilisateurObject
{
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
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 && !$this->charger($userID)) {
// Envoi d'une exception si l'utilisateur n'existe pas
throw new ImageHebergException('Utilisateur ' . $userID . ' inexistant.');
}
}
/**
* Nom d'utilisateur avec htmlentities
* @return string
*/
public function getUserName(): string
{
return htmlentities($this->userName);
}
/**
* BDD - Nom d'utilisateur non htmlentities
* @return string
*/
private function getUserNameBDD(): string
{
return $this->userName;
}
/**
* Mot de passe
* @return string
*/
private function getPassword(): string
{
return $this->password;
}
/**
* Email
* @return string
*/
public function getEmail(): string
{
return $this->email;
}
/**
* Date d'inscription
* @return string
*/
private function getDateInscription(): string
{
return $this->dateInscription;
}
/**
* Date d'inscription formatée
* @return string
*/
public function getDateInscriptionFormate(): string
{
$phpdate = strtotime($this->getDateInscription());
return date('d/m/Y', $phpdate);
}
/**
* @ IP d'inscription
* @return string
*/
public function getIpInscription(): string
{
return $this->ipInscription;
}
/**
* Niveau de droits
* @return int
*/
public function getLevel(): int
{
return $this->level;
}
/**
* ID en BDD
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* Utilisateur est actif ?
* @return bool
*/
public function getIsActif(): bool
{
return $this->isActif;
}
/**
* Token associé au compte utilisateur
* @return string
*/
public function getToken(): string
{
return $this->token;
}
/**
* Utilisateur est actif ?
* @param bool $isActif
*/
public function setIsActif(bool $isActif): void
{
$this->isActif = $isActif;
}
/**
* Token lié à l'utilisateur
* @param string $token
*/
public function setToken(string $token): void
{
$this->token = $token;
}
/**
* Nom d'utilisateur
* @param string $userName
*/
public function setUserName(string $userName): void
{
$this->userName = $userName;
}
/**
* Mot de passe
* @param string $password
*/
private function setPassword(string $password): void
{
$this->password = $password;
}
/**
* Mot de passe à crypter
* @param string $password
*/
public function setPasswordToCrypt(string $password): void
{
$this->password = password_hash($password, PASSWORD_DEFAULT);
}
/**
* Email
* @param string $email
*/
public function setEmail(string $email): void
{
$this->email = $email;
}
/**
* Date d'inscription
* @param string $dateInscription
*/
private function setDateInscription(string $dateInscription): void
{
$this->dateInscription = $dateInscription;
}
/**
* @ IP d'inscription
* @param string $ipInscription
*/
private function setIpInscription(string $ipInscription): void
{
$this->ipInscription = $ipInscription;
}
/**
* Niveau de droits
* @param int $level
*/
public function setLevel(int $level): void
{
$this->level = $level;
}
/**
* ID en BDD
* @param int $id
*/
private function setId(int $id): void
{
$this->id = $id;
}
/**
* Connexion d'un utilisateur : vérification & création de la session
* @param string $user Nom de l'utilisateur
* @param string $pwd Mot de passe associé
* @return int ID de l'utilisateur (0 si identifiants invalides)
*/
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');
$req->bindValue(':login', $user);
$req->execute();
// Je récupère les potentielles valeurs
$resultat = $req->fetch();
// Si l'utilisateur existe
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 (!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($resultat->password, hash('sha256', _GRAIN_DE_SEL_ . $pwd))) {
// Ancien mot de passe => update hash du password ;-)
$updateHash = true;
// Identifiants matchent !
$monRetour = $resultat->id;
}
} elseif (password_verify($pwd, $resultat->password)) {
// Cas standard : comparaison du hash du mot de passe fourni avec celui stocké en base
// => 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($resultat->id);
$monUtilisateur->setPasswordToCrypt($pwd);
$monUtilisateur->modifier();
}
}
return $monRetour;
}
/**
* Connexion d'un utilisateur : vérification & création de la session
* @param string $user Utilisateur
* @param string $pwd Mot de passe
* @return bool
*/
public function connexion(string $user, string $pwd): bool
{
// Protection contre une attaque : on délaie un peu l'action
usleep(500000);
// Ma session
$maSession = new SessionObject();
// Mon retour
$monRetour = false;
// Vérification des identifiants
$userID = $this->verifierIdentifiants($user, $pwd);
if ($userID) {
$monRetour = true;
// Chargement de mon utilisateur
$this->charger($userID);
// Je complète les variables de la session
$maSession->setIP($_SERVER['REMOTE_ADDR']);
$maSession->setUserObject($this);
// J'enregistre en BDD la connexion réussie
$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();
}
// Retour...
return $monRetour;
}
/**
* Charge un utilisateur depuis la BDD
* @param int $userID ID en BDD
* @return bool Utilisateur existant ?
*/
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');
$req->bindValue(':id', $userID, PDO::PARAM_INT);
$req->execute();
// Je récupère les potentielles valeurs
$resultat = $req->fetch();
// Si l'utilisateur n'existe pas... on retourne un UtilisateurObject vide
if ($resultat !== false) {
// Je charge les informations de l'utilisateur (sauf password)
$this->setId($userID);
$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;
}
return $monRetour;
}
/**
* Enregistrement (BDD) d'un utilisateur
*/
public function enregistrer(): void
{
$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']);
$req->bindValue(':lvl', $this->getLevel(), PDO::PARAM_INT);
$req->bindValue(':isActif', $this->getIsActif(), PDO::PARAM_BOOL);
$req->bindValue(':token', $this->getToken());
$req->execute();
}
/**
* Modifier (BDD) un utilisateur déjà existant
*/
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());
$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());
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
$req->execute();
}
/**
* Suppression (BDD) d'un utilisateur
*/
public function supprimer(): void
{
// Les images possédées
$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 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->bindValue(':id', $this->getId(), PDO::PARAM_INT);
$req->execute();
}
/**
* Assigne une image à un utilisateur en BDD
* @param ImageObject $imageObject
* @throws ImageHebergException
*/
public function assignerImage(ImageObject $imageObject): void
{
if ($this->getId() === 0) {
throw new ImageHebergException('Aucun utilisateur n\'est défini !');
}
// Les images possédées
$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 string $login
* @return bool
*/
public static function verifierLoginDisponible(string $login): bool
{
$req = MaBDD::getInstance()->prepare('SELECT * FROM membres WHERE login = :login');
$req->bindValue(':login', $login);
$req->execute();
// Par défaut le login est disponible
$monRetour = true;
// Si j'ai un résultat...
if ($req->fetch()) {
// Le retour est négatif
$monRetour = false;
}
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
* @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(int $levelRequis, bool $dieIfNotGranted = true)
{
$monRetour = false;
$monUser = new SessionObject();
if ($monUser->verifierDroits($levelRequis) === false) {
// 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
* @return ArrayObject new_name image
*/
public function getImages(): ArrayObject
{
// Toutes les images
$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();
$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;
}
}

View file

@ -0,0 +1,242 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
/**
* Les images
*/
class imageObject extends ressourceObject implements ressourceInterface {
/**
* Constructeur
* @param string $newName nom de l'image
*/
function __construct($newName = FALSE) {
// Définition du type pour le ressourceObject
$this->setType(ressourceObject::typeImage);
// 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');
}
}
}
/**
* {@inheritdoc}
*/
public function charger($newName) {
// Retour
$monRetour = FALSE;
// 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();
// 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);
// Gestion du retour
$monRetour = TRUE;
}
return $monRetour;
}
/**
* {@inheritdoc}
*/
public function sauver() {
// 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->bindValue(':dateEnvoi', $this->getDateEnvoiBrute());
$req->bindValue(':oldName', $this->getNomOriginal(), PDO::PARAM_STR);
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STR);
$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(':isBloquee', $this->isBloquee(), PDO::PARAM_INT);
$req->bindValue(':isSignalee', $this->isSignalee(), PDO::PARAM_INT);
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
$req->execute();
}
/**
* {@inheritdoc}
*/
public function supprimer() {
$monRetour = TRUE;
/**
* 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);
$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) {
// Existe-t-il d'autres occurences de cette image ?
$req = maBDD::getInstance()->prepare("SELECT COUNT(*) AS nb FROM images WHERE md5 = :md5");
/* @var $req PDOStatement */
$req->bindValue(':md5', $this->getMd5(), PDO::PARAM_STR);
$req->execute();
$values = $req->fetch();
// Il n'y a plus d'image identique...
if ($values !== FALSE && (int) $values->nb === 0) {
// Je supprime l'image sur le HDD
$monRetour = unlink($this->getPathMd5());
} elseif ($values === FALSE) {
$monRetour = FALSE;
}
}
return $monRetour;
}
/**
* {@inheritdoc}
*/
public function creer() {
/**
* Détermination du nom &&
* Vérification de sa disponibilité
*/
$tmpImage = new imageObject();
$nb = 0;
do {
// Récupération d'un nouveau nom
$new_name = $this->genererNom($nb);
// Incrémentation compteur entropie sur le nom
$nb++;
} while ($tmpImage->charger($new_name) !== FALSE);
// Effacement de l'objet temporaire
unset($tmpImage);
// On enregistre le nom
$this->setNomNouveau($new_name);
/**
* Déplacement du fichier
*/
// Chargement de l'image + enregistrement : permet de réduire la taille
$monRetour = outils::setImage(outils::getImage($this->getPathTemp()), outils::getType($this->getPathTemp()), $this->getPathMd5());
// Ssi copie du fichier réussie
if ($monRetour) {
/**
* Informations sur l'image
*/
// Dimensions
$imageInfo = getimagesize($this->getPathMd5());
$this->setLargeur($imageInfo[0]);
$this->setHauteur($imageInfo[1]);
// Poids
$this->setPoids(filesize($this->getPathMd5()));
// Nom originel (non récupérable sur le fichier)
$this->setNomOriginal($this->getNomTemp());
// @ IP d'envoi
$this->setIpEnvoi($_SERVER['REMOTE_ADDR']);
/**
* 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);
// Date : NOW()
$req->bindValue(':oldName', $this->getNomOriginal(), PDO::PARAM_STR);
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STR);
$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);
if (!$req->execute()) {
// Gestion de l'erreur d'insertion en BDD
$monRetour = FALSE;
} else {
/**
* Récupération de l'ID de l'image
*/
$idEnregistrement = maBDD::getInstance()->lastInsertId();
$this->setId($idEnregistrement);
}
}
return $monRetour;
}
}

86
classes/maBDD.class.php Normal file
View file

@ -0,0 +1,86 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
/**
* Lien vers la BDD
*
* @author anael
*/
class maBDD {
// PDO
private $maBDD = null;
// Instance de la classe
private static $monInstance = null;
/**
* Constructeur
*/
private function __construct() {
$this->maBDD = new PDO('mysql:host=' . _BDD_HOST_ . ';dbname=' . _BDD_NAME_, _BDD_USER_, _BDD_PASS_);
$this->maBDD->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->maBDD->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
/**
* Crée & renvoi l'objet d'instance
* @return PDO
*/
public static function getInstance() {
// Si pas de connexion active, en crée une
if (is_null(self::$monInstance)) {
self::$monInstance = new maBDD();
}
return self::$monInstance;
}
/**
* PDO::query
* @param type $query
* @return type
*/
public function query($query) {
return $this->maBDD->query($query);
}
/**
* PDO::prepare
* @param type $query
* @return type
*/
public function prepare($query) {
return $this->maBDD->prepare($query);
}
/**
* PDO::lastInsertId
* @return type
*/
public function lastInsertId() {
return $this->maBDD->lastInsertId();
}
/**
* Fermeture du PDO
*/
public static function close() {
self::$monInstance = null;
}
}

View file

@ -0,0 +1,265 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
/**
* 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;
}
/**
* Toutes les images appartenant à un utilisateur
* @param type $userId ID de l'user en question
* @return \ArrayObject new_name image
*/
public static function getAllPicsOffOneUser($userId) {
// 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', $userId, PDO::PARAM_INT);
// Exécution de la requête
$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;
}
/**
* Vérifie que l'utilisateur à le droit d'afficher la page et affiche un EM au cas
* @param type $levelRequis
*/
public static function checkUserAccess($levelRequis) {
$monUser = new sessionObject();
if ($monUser->verifierDroits($levelRequis) === FALSE) {
require _TPL_TOP_;
?>
<h1>Accès refusé</h1>
<p>Désolé, vous n'avez pas le droit d'accèder à cette page.</p>
<?php
require _TPL_BOTTOM_;
die();
}
}
/**
* Vérifier si un login est disponible pour enregistrement
* @param type $login
* @return boolean
*/
public static function verifierLoginDisponible($login) {
$req = maBDD::getInstance()->prepare("SELECT * FROM membres WHERE login = :login");
/* @var $req PDOStatement */
$req->bindValue(':login', $login, PDO::PARAM_STR);
$req->execute();
// Par défaut le login est disponible
$retour = TRUE;
// Si j'ai un résultat...
if ($req->fetch()) {
// Le retour est négatif
$retour = FALSE;
}
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;
}
}

View file

@ -0,0 +1,229 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
/**
* Les miniatures
*/
class miniatureObject extends ressourceObject implements ressourceInterface {
private $idImage;
/**
* Constructeur
* @param string $newName newName de l'image maître
*/
function __construct($newName = FALSE) {
// Définition du type pour le ressourceObject
$this->setType(ressourceObject::typeMiniature);
// 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');
}
}
}
/**
* {@inheritdoc}
*/
public function charger($newName) {
$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_INT);
$req->execute();
// J'éclate les informations
$resultat = $req->fetch();
if ($resultat !== FALSE) {
$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->setId($resultat->id);
$this->setDateEnvoi($resultat->date_creation);
$this->setNomNouveau($newName);
$this->setIdImage($resultat->id_image);
// 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());
// Notification du chargement réussi
$monRetour = TRUE;
}
return $monRetour;
}
/**
* {@inheritdoc}
*/
public function sauver() {
// 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->bindValue(':idImage', $this->getIdImage(), PDO::PARAM_INT);
$req->bindValue(':dateCreation', $this->getDateEnvoiBrute());
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STMT);
$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(':id', $this->getId(), PDO::PARAM_INT);
$req->execute();
}
/**
* {@inheritdoc}
*/
public function supprimer() {
$monRetour = TRUE;
/**
* Suppression de l'image en BDD
*/
$req = maBDD::getInstance()->prepare("DELETE FROM thumbnails WHERE id = :id");
/* @var $req PDOStatement */
$req->bindValue(':id', $this->getId(), PDO::PARAM_INT);
$monRetour = $req->execute();
/**
* Suppression du HDD
*/
if ($monRetour) {
// Existe-t-il d'autres occurences de cette image ?
$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();
// Il n'y a plus d'image identique...
if ($values !== FALSE && (int) $values->nb === 0) {
// Je supprime l'image sur le HDD
$monRetour = unlink($this->getPathMd5());
} elseif ($values === FALSE) {
$monRetour = FALSE;
}
}
return $monRetour;
}
/**
* {@inheritdoc}
*/
public function creer() {
/**
* Détermination du nom &&
* Vérification de sa disponibilité
*/
$tmpMiniature = new miniatureObject();
$nb = 0;
do {
// Récupération d'un nouveau nom
$new_name = $this->genererNom($nb);
// Incrémentation compteur entropie sur le nom
$nb++;
} while ($tmpMiniature->charger($new_name) !== FALSE);
// Effacement de l'objet temporaire
unset($tmpMiniature);
// On enregistre le nom
$this->setNomNouveau($new_name);
/**
* Déplacement du fichier
*/
$monRetour = rename($this->getPathTemp(), $this->getPathMd5());
// Ssi copie du fichier réussie
if ($monRetour) {
/**
* Informations sur l'image
*/
// Dimensions
$imageInfo = getimagesize($this->getPathMd5());
$this->setLargeur($imageInfo[0]);
$this->setHauteur($imageInfo[1]);
// Poids
$this->setPoids(filesize($this->getPathMd5()));
/**
* 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);
// Date : NOW()
$req->bindValue(':newName', $this->getNomNouveau(), PDO::PARAM_STR);
$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);
if (!$req->execute()) {
// Gestion de l'erreur d'insertion en BDD
$monRetour = FALSE;
} else {
/**
* Récupération de l'ID de l'image
*/
$idEnregistrement = maBDD::getInstance()->lastInsertId();
$this->setId($idEnregistrement);
}
}
return $monRetour;
}
/**
* GETTERS & SETTERS
*/
/**
* ID image parente
* @return int
*/
public function getIdImage() {
return $this->idImage;
}
/**
* ID image parente
* @param int $idImage
*/
public function setIdImage($idImage) {
$this->idImage = $idImage;
}
}

262
classes/outils.class.php Normal file
View file

@ -0,0 +1,262 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
/**
* 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);
break;
case IMAGETYPE_PNG:
$monImage = imagecreatefrompng($path);
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:
$monRetour = imagejpeg($uneImage, $path, 100);
break;
case IMAGETYPE_PNG:
$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;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}
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;
}
/**
* Vérifie l'existence de l'image pour :
* @param string $unMD5 le md5 du fichier
* @param string $uneIp l'adresse IP d'envoi
* @param int $typeImage ressourceObject::const Type de l'image
* @return string|NULL Nom de l'image si déjà présente
*/
public static function verifierRenvoiImage($unMD5, $uneIp, $typeImage) {
$monRetour = NULL;
// Info de l'utilisateur
$maSession = new sessionObject();
/**
* IMAGE
*/
if ($typeImage === ressourceObject::typeImage) {
if ($maSession->getLevel() === utilisateurObject::levelGuest) {
/**
* Utilisateur anonyme
* Recherche sur MD5, @IP (sauf images possédées) sur les 15 derniers jours !
*/
$req = maBDD::getInstance()->prepare("SELECT new_name FROM images WHERE md5 = :md5 AND ip_envoi = :ipEnvoi AND date_envoi > DATE_SUB(NOW(), INTERVAL 15 DAY) AND id NOT IN (SELECT image_id from possede) ORDER BY date_envoi DESC");
/* @var $req PDOStatement */
$req->bindValue(':md5', $unMD5, PDO::PARAM_STR);
$req->bindValue(':ipEnvoi', $uneIp, PDO::PARAM_STR);
} else {
/**
* Utilisateur authentifié
* Recherche sur MD5, possede (sur ses images)
*/
$req = maBDD::getInstance()->prepare("SELECT new_name FROM images, possede, membres WHERE md5 = :md5 AND images.id = possede.image_id AND possede.pk_membres = membres.id AND membres.id = :id ORDER BY date_envoi DESC");
/* @var $req PDOStatement */
$req->bindValue(':md5', $unMD5, PDO::PARAM_STR);
$req->bindValue(':id', $maSession->getId(), PDO::PARAM_INT);
}
}
/**
* MINIATURE
*/ else {
if ($maSession->getLevel() === utilisateurObject::levelGuest) {
/**
* Utilisateur anonyme
* Recherche sur MD5, @IP (sauf images possédées)
*/
$req = maBDD::getInstance()->prepare("SELECT thumbnails.new_name FROM thumbnails, images WHERE thumbnails.md5 = :md5 AND images.ip_envoi = :ipEnvoi AND thumbnails.date_creation > DATE_SUB(NOW(), INTERVAL 15 DAY) AND id_image NOT IN (SELECT image_id from possede) AND thumbnails.id_image = images.id ORDER BY date_envoi DESC");
/* @var $req PDOStatement */
$req->bindValue(':md5', $unMD5, PDO::PARAM_STR);
$req->bindValue(':ipEnvoi', $uneIp, PDO::PARAM_STR);
} else {
/**
* Utilisateur authentifié
* Recherche sur MD5, possede (sur ses images)
*/
$req = maBDD::getInstance()->prepare("SELECT thumbnails.new_name FROM thumbnails, images, possede, membres WHERE thumbnails.md5 = :md5 AND images.id = possede.image_id AND possede.pk_membres = membres.id AND membres.id = :id AND thumbnails.id_image = images.id ORDER BY date_envoi DESC");
/* @var $req PDOStatement */
$req->bindValue(':md5', $unMD5, PDO::PARAM_STR);
$req->bindValue(':id', $maSession->getId(), PDO::PARAM_INT);
}
}
// Exécution de la requête
$req->execute();
// Je récupère les potentielles valeurs
$values = $req->fetch();
if ($values !== FALSE) {
// Données éventuelles
$monRetour = $values->new_name;
}
return $monRetour;
}
}

View file

@ -1,7 +1,6 @@
<?php
/*
* Copyright 2008-2024 Anael MOBILIA
* Copyright 2008-2019 Anael Mobilia
*
* This file is part of image-heberg.fr.
*
@ -19,34 +18,33 @@
* along with image-heberg.fr. If not, see <http://www.gnu.org/licenses/>
*/
namespace ImageHeberg;
/**
* Fonctions devant êtres implémentées spécifiquement par les images et miniatures
*/
interface RessourceInterface
{
/**
* Crée sur le HDD et dans la BDD la ressource
* @return bool Résultat ?
*/
public function creer(): bool;
interface ressourceInterface {
/**
* 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(string $value, string $fromField = RessourceObject::SEARCH_BY_NAME): bool;
/**
* Crée sur le HDD et dans la BDD la ressource
* @return boolean Résultat ?
*/
function creer();
/**
* Enregistre en BDD un objet ressource
*/
public function sauver(): void;
/**
* Charge unn objet ressource depuis la BDD
* @param string $nom Identifiant image-heberg
* @return boolean Résultat ?
*/
function charger($nom);
/**
* Supprime sur le HDD et dans la BDD la ressource
*/
public function supprimer(): void;
}
/**
* Enregistre en BDD un objet ressource
* @return boolean Résultat ?
*/
function sauver();
/**
* Supprime sur le HDD et dans la BDD la ressource
* @return boolean Résultat ?
*/
function supprimer();
}

View file

@ -0,0 +1,585 @@
<?php
/*
* Copyright 2008-2019 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/>
*/
/**
* Fonctions génériques aux images et miniatures
*/
abstract class ressourceObject {
const typeImage = 1;
const typeMiniature = 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;
/**
* 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
*/
protected function genererNom($nb = 0) {
// Random pour unicité + cassage lien nom <-> @IP
$random = rand(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());
return $new_name;
}
/**
* MD5 de la ressource
* @return string
*/
public function getMd5() {
// Création d'une image
if (is_null($this->md5)) {
// Fichier temporaire...
$this->md5 = md5_file($this->getPathTemp());
}
return $this->md5;
}
/**
* Path sur le HDD
* @return string
*/
public function getPathMd5() {
// Path final
$pathFinal = '';
// Path du type d'image
$pathDuType = '';
if ($this->getType() === self::typeImage) {
// Image
$pathDuType = _PATH_IMAGES_;
} else {
// Miniature
$pathDuType = _PATH_MINIATURES_;
}
if ($this->getType() === self::typeImage && ($this->getId() === 1 || $this->getId() === 2)) {
// Gestion des images spécificques 404 / ban
$pathFinal = $pathDuType . $this->getNomNouveau();
} else {
// Cas par défaut
$rep = substr($this->getMd5(), 0, 1) . '/';
$pathFinal = $pathDuType . $rep . $this->getMd5();
}
return $pathFinal;
}
/**
* URL de la ressource
* @return string
*/
public function getURL() {
// Path du type d'image
$urlDuType = '';
if ($this->getType() === self::typeImage) {
// Image
$urlDuType = _URL_IMAGES_;
} else {
// Miniature
$urlDuType = _URL_MINIATURES_;
}
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 string $pathSrc chemin de la ressource d'origine
* @param string $pathDst chemin de la ressource de destination
* @return boolean succès ?
*/
function rotation($angle, $pathSrc, $pathDst) {
// Je charge l'image en mémoire
$resImg = outils::getImage($pathSrc);
// Je vérifie que tout va bien
if ($resImg === FALSE) {
return FALSE;
}
// 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;
}
/**
* Redimensionne une image en respectant le ratio de l'image original
* @param string $pathSrc chemin de la ressource d'origine
* @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 ?
*/
public function redimensionner($pathSrc, $pathDst, $largeurDemandee, $hauteurDemandee) {
// Chargement de l'image
$monImage = outils::getImage($pathSrc);
// Récupération de ses dimensions
$largeurImage = imagesx($monImage);
$hauteurImage = imagesy($monImage);
// Dimension nulle : 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));
} else {
// Format portrait ou carré
$largeurMax = min(array($largeurDemandee, $hauteurDemandee));
$hauteurMax = max(array($largeurDemandee, $hauteurDemandee));
}
// Calcul du ratio
$monRatio = min(array($largeurMax / $largeurImage, $hauteurMax / $hauteurImage));
// Dimensions finales
$largeurFinale = round($largeurImage * $monRatio);
$hauteurFinale = round($hauteurImage * $monRatio);
// Debug
if (_TRAVIS_) {
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;
}
/**
* Cet utilisateur est-il propriétaire de l'image ?
* @return boolean
*/
public function isProprietaire() {
$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) {
// Le propriétaire est-il connecté ?
$uneSession = new sessionObject();
// Est-ce le propriétaire de l'image ?
if ((int) $values->pk_membres === $uneSession->getId()) {
// Si oui... on confirme !
$monRetour = TRUE;
}
}
return $monRetour;
}
/**
* Date d'envoi formatée
* @return string
*/
public function getDateEnvoiFormatee() {
$phpdate = strtotime($this->getDateEnvoiBrute());
return date("d/m/Y H:i:s", $phpdate);
}
/**
* Date de dernier affichage formaté
* @return string
*/
public function getLastViewFormate() {
$phpdate = strtotime($this->getLastView());
// Gestion du cas de non affichage
if ($phpdate === 0) {
return "-";
}
return date("d/m/Y", $phpdate);
}
/**
* Nombre d'appels IPv4 & IPv6
* @return int
*/
public function getNbViewTotal() {
return (int) $this->getNbViewIPv4() + $this->getNbViewIPv6();
}
/**
* Nom original de la ressource
* @return string
*/
public function getNomOriginalFormate() {
return htmlentities($this->nomOriginal);
}
/**
* Incrémente le nombre d'affichage IPv4
*/
public function setNbViewIpv4PlusUn() {
$this->nbViewIPv4 = $this->getNbViewIPv4() + 1;
$this->setLastView(date("Y-m-d"));
}
/**
* Incrémente le nombre d'affichage IPv6
*/
public function setNbViewIpv6PlusUn() {
$this->nbViewIPv6 = $this->getNbViewIPv6() + 1;
$this->setLastView(date("Y-m-d"));
}
/**
* GETTERS ET SETTERS
*/
/**
* ID de la ressource
* @return int
*/
public function getId() {
return (int) $this->id;
}
/**
* Nom original de la ressource
* @return string
*/
protected function getNomOriginal() {
return $this->nomOriginal;
}
/**
* Nom image-heberg
* @return string
*/
public function getNomNouveau() {
return $this->nomNouveau;
}
/**
* Largeur en px
* @return int
*/
public function getLargeur() {
return (int) $this->largeur;
}
/**
* Hauteur en px
* @return int
*/
public function getHauteur() {
return (int) $this->hauteur;
}
/**
* Poids de la ressource
* @return int
*/
public function getPoids() {
return (int) $this->poids;
}
/**
* Date de dernier affichage
* @return type
*/
protected function getLastView() {
return $this->lastView;
}
/**
* Nb d'affichage en IPv4
* @return int
*/
protected function getNbViewIPv4() {
return (int) $this->nbViewIPv4;
}
/**
* Nb d'affichage en IPv6
* @return int
*/
protected function getNbViewIPv6() {
return (int) $this->nbViewIPv6;
}
/**
* Date d'envoi du fichier
* @return type
*/
public function getDateEnvoiBrute() {
return $this->dateEnvoi;
}
/**
* @ IP d'envoi
* @return string
*/
public function getIpEnvoi() {
return $this->ipEnvoi;
}
/**
* Image bloquée ?
* @return boolean
*/
public function isBloquee() {
return $this->isBloquee;
}
/**
* Image signalée ?
* @return boolean
*/
function isSignalee() {
return $this->isSignalee;
}
/**
* Path temporaire (upload d'image)
* @return string
*/
public function getPathTemp() {
return $this->pathTemp;
}
/**
* Type d'image
* @return int ressoruceObject const
*/
public function getType() {
return $this->type;
}
/**
* Nom temporaire (PC utilisateur - upload d'image)
* @return string
*/
public function getNomTemp() {
return $this->nomTemp;
}
/**
* Nom temporaire (PC utilisateur - upload d'image)
* @param string $nomTemp
*/
public function setNomTemp($nomTemp) {
$this->nomTemp = $nomTemp;
}
/**
* Type d'image
* @param int $type ressourceObject const
*/
public function setType($type) {
$this->type = $type;
}
/**
* Path temporaire (upload d'image)
* @param string $pathTemp
*/
public function setPathTemp($pathTemp) {
$this->pathTemp = $pathTemp;
}
/**
* Image bloquée ?
* @param boolean $bloquee
*/
public function setBloquee($bloquee) {
$this->isBloquee = $bloquee;
}
/**
* Image signalée ?
* @param boolean $isSignalee
*/
function setSignalee($isSignalee) {
$this->isSignalee = $isSignalee;
}
/**
* ID de l'image
* @param int $id
*/
protected function setId($id) {
$this->id = $id;
}
/**
* Nom original de la ressource
* @param string $nomOriginal
*/
protected function setNomOriginal($nomOriginal) {
$this->nomOriginal = $nomOriginal;
}
/**
* Nom image-heberg
* @param string $nomNouveau
*/
protected function setNomNouveau($nomNouveau) {
$this->nomNouveau = $nomNouveau;
}
/**
* Largeur en px
* @param int $largeur
*/
protected function setLargeur($largeur) {
$this->largeur = $largeur;
}
/**
* Hauteur en px
* @param int $hauteur
*/
protected function setHauteur($hauteur) {
$this->hauteur = $hauteur;
}
/**
* Poids de la ressource
* @param int $poids
*/
protected function setPoids($poids) {
$this->poids = $poids;
}
/**
* Date de dernier affichage
* @param type $lastView
*/
protected function setLastView($lastView) {
$this->lastView = $lastView;
}
/**
* Nb d'affichage en IPv4
* @param int $nbViewIPv4
*/
protected function setNbViewIPv4($nbViewIPv4) {
$this->nbViewIPv4 = $nbViewIPv4;
}
/**
* Nb d'affichage en IPv6
* @param int $nbViewIPv6
*/
protected function setNbViewIPv6($nbViewIPv6) {
$this->nbViewIPv6 = $nbViewIPv6;
}
/**
* Date d'envoi du fichier
* @param type $dateEnvoi
*/
protected function setDateEnvoi($dateEnvoi) {
$this->dateEnvoi = $dateEnvoi;
}
/**
* MD5 de la ressource
* @param string $md5
*/
protected function setMd5($md5) {
$this->md5 = $md5;
}
/**
* @ IP d'envoi
* @param string $ipEnvoi
*/
protected function setIpEnvoi($ipEnvoi) {
$this->ipEnvoi = $ipEnvoi;
}
}

Some files were not shown because too many files have changed in this diff Show more