Système de Gestion-Affichage de Nouvelles

Avec éditeur WYSIWYG, photo et fichier joint

Image non disponible

PHP - Système de Gestion-Affichage de Nouvelles (Articles, Actualités...) :

Version 4 (MYSQL/Procédural)
Version 5 (PDO/Procédural)

Ce système de Nouvelles avec photo et fichier joint vous permettra de gérer vous-même votre news, actualité, info... et devrait s'intégrer facilement dans votre site.
La possibilité d'ajouter une photo, de joindre un fichier et la mise en forme grâce à un éditeur WYSIWYG sont des plus !
406 commentaires Donner une note à l'article (4.5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

1. Système de Gestion-Affichage de Nouvelles

1-A. Objectifs

Mon objectif est de vous proposer une base de départ pour le développement de votre propre système de News.

Ce système de Gestion-Affichage de Nouvelles/Articles vous permettra :
-> d'installer rapidement et facilement un affichage de Nouvelles/articles pour votre site ;
-> d'ajouter tout aussi facilement une photo et/ou un fichier joint ;
-> de formater le contenu grâce à l'éditeur WYSIWYG de votre choix ;
-> de publier ou dépublier un Article ;
-> de configurer l'affichage à votre convenance (sur 1 ou plusieurs colonnes, avec résumé, pagination,...) ;

Cette source est parfaitement fonctionnelle en l'état.
Elle est aussi (et surtout !) prévue pour être intégrée facilement dans votre site.

Cette source est aussi un tutoriel.
Les fichiers contiennent de nombreux commentaires et explications, qui ont aussi une valeur pédagogique : « copier-coller, c'est bien, comprendre, c'est mieux ».
N'hésitez pas à jeter un œil au code !

Image non disponible

Ces fichiers sont open source, vous pouvez donc les modifier à votre convenance.

1-B. Mise à jour le 20/11/2015 - Améliorations apportées

Pour ceux qui auraient téléchargé les anciennes versions, voici la liste des améliorations apportées :

  • Encodage en UTF-8 (site et base de données) ;
  • Installation simplifiée : réorganisation complète et plus claire des dossiers/fichiers ;
  • Configuration et paramétrages personnels : via un fichier de config clair, commenté et complet;
  • Affichage des Nouvelles (listing) : sur une ou plusieurs colonnes, avec résumé du contenu, pagination,...;
  • Authentification (Administration) : (au choix) simple (1 seul utilisateur) ou via la base de données (avec mot de passe crypté);
  • Fonctions : optimisation des tâches répétitives (fiche/listing des Nouvelles, résumé de texte, redimensionnement des photos...) ;
  • Upload sécurisé : vérification des extensions ET type MIME (avant upload) ;
  • Formulaires : vérification/sécurisation des données transmises ;
  • Ergonomie : prise en main intuitive ;
  • Design : interface Administration plus... stylée (un peu de CSS3) ;
  • Nécessite PHP 5 ou supérieur ;
  • Validation W3C.

1-C. Version 4 (MYSQL/Procédural)

  • Programmation en langage PHP procédural ;
  • Connexion à la base de données via l'extension mysql.
  • Encodage en UTF-8 (site et base de données) ;
  • Nécessite PHP 5 ou supérieur ;

L'extension mysql_ est OBSOLETE, et ne devrait plus être utilisée !
Voir mysql :
"Cette extension n'est pas recommandé pour écrire du nouveau code. A la place, soit l'extension mysqli ou PDO_MySQL devrait être utilisée."
Ce qui justifie la création de la version 5 de la présente source.

Cependant, si votre site est sur free.fr, la version 5 ne fonctionnera pas correctement (selon mes derniers essais).
La version 4 n'est donc pas tout-à-fait obsolète...

1-D. Version 5 (PDO/Procédural)

  • Programmation en langage PHP procédural ;
  • Connexion à la base de données via PDO (PHP Data Objects) : requêtes préparées = sécurité ! ;
  • Encodage en UTF-8 (site et base de données) ;
  • Nécessite PHP 5 ou supérieur ;

La Version 5 (PDO/Procédural), avec PDO, est à privilégier !

1-E. Version 6 (PDO/POO) : à venir (?)

Une version en POO (Programmation Orientée Objet) est en cours... ...dès que j'aurais compris et maitrisé la POO... ;)

2. Installation, démonstration

2-A. Téléchargez l'archive, testez la démonstration en ligne

  • N'hésitez pas à tester la démo en ligne !
  • Téléchargez l'archive zip ; dézippez ;
  • Copiez les dossiers/fichiers à la racine de votre site.

NB : Si vous renommez les dossiers, déplacez les fichiers selon votre propre configuration : attention à modifier partout les chemins et liens dans les fichiers de configuration !

PHP : Système de Gestion-Affichage de Nouvelles Téléchargement (archive zip) Testez la démo
Version 5.5 : PDO/Procédural PHP-GESTION-NEWS-v5-PDO-Procedural.zipPHP-GESTION-NEWS-v5-PDO-Procedural.zip ( miroirPHP-GESTION-NEWS-v5-PDO-Procedural.zip ) Démo Version 5Démo Version 5
Version 4.4 : MYSQL/Procédural PHP-GESTION-NEWS-v4-MYSQL-Procedural.zipPHP-GESTION-NEWS-v4-MYSQL-Procedural.zip ( miroirPHP-GESTION-NEWS-v4-MYSQL-Procedural.zip )
Démo Version 4Démo Version 4
Vous pouvez déposer vos commentaires ou poser vos questions sur cette source : 406 commentaires Donner une note à l'article (4.5)


Configuration requise : nécessite PHP 5 ou supérieur.
Vous pouvez tester votre configuration serveur en lancant le fichier phpinfo.php (inclus), ou en tapant :

phpinfo.php
Sélectionnez
<?php echo phpinfo(); ?>

2-B. Organisation des dossiers/fichiers

Vue d'ensemble :

Dossier modules/mod_news fichiers spécifiques à l'affichage de la News
Dossier admin/adm_mod_news fichiers spécifiques à l'administration de la News
Dossier config configuration principale du site et de la connexion à votre base de données
Dossier fonctions fonctions principales nécessaires (formatage des données, redimensionnement des photos,...)
Dossier template thème/images/CSS du site (à remplacer par le votre)
Dossier upload
Dossier upload/images/news_photos
Dossier upload/files/news_files
stockage des images et fichiers téléchargés
- stockage des photos (par défaut : jpg, jpeg, png, gif)
- stockage des fichiers (par défaut : pdf)
Ces dossiers doivent être déprotégés en écriture (chmod : 777)
Dossier utilitaires
éditeurs WYSIWYG intégrés (au choix) :
aucun (texte simple), CKeditor(3.6.3), TinyMCE (3.5.5)

3. Configuration

3-A. Configuration de la Base de Données

Configuration de la connexion à la Base de Données :
config/_connexion.php
- configurez les paramètres de connexion à votre base de données ;


Version 4 (MYSQL) (encodage UTF-8)

config/_connexion.php
Sélectionnez
<?php
// --------------------------------------------------------------
// Paramètres de connection a la Base de Données sur le serveur
// --------------------------------------------------------------
$connexion = array();
$connexion['hostname'] = 'localhost'; 		// voir hébergeur ou "localhost" en local
$connexion['database'] = 'ma_base_news'; 	// nom de la BdD
$connexion['username'] = 'root'; 			// identifiant "root" en local
$connexion['password'] = ''; 				// mot de passe (vide en local)
// --------------------------------------------------------------
// connexion à la base de données
$connexion_db = 
	mysql_connect($connexion['hostname'],$connexion['username'],$connexion['password']) 
	or die ('Erreur de paramètres de connexion à la BD');
mysql_select_db($connexion['database'],$connexion_db)or die ('Erreur de connexion a la BD');
mysql_set_charset( 'utf8' ); // encodage UTF-8
// ------------------------
$connexion = array(); // on vide
// --------------------------------------------------------------

Version 5 (PDO) (encodage UTF-8)

config/_connexion.php
Sélectionnez
<?php
// --------------------------------------------------------------
// Paramètres de connection à la Base de Données sur le serveur
// --------------------------------------------------------------
	$pdo_conn				= array();
	$pdo_conn['hostname']	= 'localhost';		// voir hébergeur ou "localhost" en local
	$pdo_conn['database']	= 'ma_base_news'; 	// nom de la BdD
	$pdo_conn['username']	= 'root';			// identifiant "root" en local
	$pdo_conn['password']	= '';				// mot de passe (vide en local)
// ------------------------
// connexion à la Base de Données
try {
	// chaine de connexion (DSN)
	$pdo_conn['strConn'] 	= 'mysql:host='.$pdo_conn['hostname'].';dbname='.$pdo_conn['database'];
	$pdo_conn['extraParam']	= array(
							PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,		// rapport d'erreurs sous forme d'exceptions
							PDO::ATTR_PERSISTENT => true, 						// Connexions persistantes
							PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"	// encodage UTF-8
							);
	// Instancie la connexion
	$pdo = new PDO($pdo_conn['strConn'], $pdo_conn['username'], $pdo_conn['password'], $pdo_conn['extraParam']);
}
catch(PDOException $e){
	$msg = 'ERREUR PDO dans ' . $e->getFile().' L.' . $e->getLine().' : ' . $e->getMessage();
	die($msg);
}
// ------------------------
	$pdo_conn				= array();	// on vide
// --------------------------------------------------------------

3-B. Création des tables

Création des tables nécessaires dans la Base de Données :
modules/mod_news/news_config_tableSQL.txt
- créez manuellement les tables nécessaires dans votre base de données ;
- NB : si vous renommez les tables, pensez à changer les noms dans : modules/mod_news/news_config.php ;


Création de la table des News : NEWS_TABLE_PHPV5 :

table des News : NEWS_TABLE_PHPV5
Sélectionnez

-- --------------------------------------------------------
-- Structure de la table `NEWS_TAB_ARTICLES`
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `NEWS_TAB_ARTICLES` (
  `news_id` int(10) NOT NULL AUTO_INCREMENT,
  `news_titre` varchar(255) NOT NULL DEFAULT '',
  `news_contenu` text NOT NULL,
  `news_date` int(5) NOT NULL,
  `news_photo` varchar(255) DEFAULT NULL COMMENT 'URL de la Photo',
  `news_photo_largeur` int(2) NOT NULL DEFAULT '100',
  `news_file` varchar(255) DEFAULT NULL COMMENT 'URL du Fichier',
  `news_publier` int(2) NOT NULL DEFAULT '1' COMMENT 'publier : 1=oui 0=non',
  PRIMARY KEY (`news_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
-- --------------------------------------------------------

Création de la table de connexion : NEWS_ADM_CONNEXION : (voir la section Accès à la partie Administration)

table de connexion : NEWS_ADM_CONNEXION
Sélectionnez

-- --------------------------------------------------------
-- Structure de la table `NEWS_ADM_CONNEXION`
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `NEWS_ADM_CONNEXION` (
  `id_conn` int(10) NOT NULL AUTO_INCREMENT,
  `id_statut` int(2) NOT NULL DEFAULT '1' COMMENT '1-9 (10=superadmin)',
  `log_admin` varchar(100) NOT NULL DEFAULT '',
  `pwd_admin` varchar(200) NOT NULL DEFAULT '',
  `controle` varchar(50) DEFAULT NULL COMMENT 'Laisser VIDE en production !',
  `nom_admin` varchar(100) NOT NULL,
  `prenom_admin` varchar(100) NOT NULL,
  `email_admin` varchar(150) NOT NULL,
  PRIMARY KEY (`id_conn`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 PACK_KEYS=0 AUTO_INCREMENT=2 ;

--
-- Contenu de la table `NEWS_ADM_CONNEXION`
-- ==> Par sécurité, la modification devra se faire MANUELLEMENT directement dans la base de données
-- ==> Générer un mot de passe hashé : admin/adm-createpwd.php
--

INSERT INTO `NEWS_ADM_CONNEXION` (`id_conn`, `id_statut`, `log_admin`, `pwd_admin`, `controle`, `nom_admin`, `prenom_admin`, `email_admin`) VALUES
(1, 10, 'Newslogin', '$2y$10$iPVFwNk2.BvztwpK0xQSdONFHmv/ceVmvBKOhq8qDoEhMD5d78PJK', 'Newspwd', 'Version démo', '', '');
-- --------------------------------------------------------

Sécurité :
Le champ "controle" peut être supprimé (il contient le mot de passe en clair, mais n'est jamais transmis).

Générer un mot de passe hashé :
admin/adm-createpwd.php

Ce fichier "caché" n'est accessible qu'en tapant directement http:/.../admin/adm-createpwd.php dans la barre d'adresse de votre navigateur.
Il n'a aucun lien direct avec le reste des fichiers (pas de modification automatique).
Par sécurité, la modification devra donc se faire MANUELLEMENT, directement dans la base de données.

3-C. Configuration, paramétrages personnels pour l'affichage/la gestion des Nouvelles

Configuration, paramétrages personnels :
modules/mod_news/news_config.php


- nom de la table des News : `NEWS_TAB_ARTICLES` (par défaut);
- nom de la table de connexion à l'Administration des News : `NEWS_ADM_CONNEXION` (par défaut);;
- paramètres d'affichage de la News : nombre de colonnes, pagination, résumé du texte, format des miniatures,... ;
- photo, fichier : dossiers, restrictions, extensions acceptées, type MIME acceptés ;
- choix de votre éditeur WYSIWYG ;
Configuration principale :
config/main_config.php
- chemin principal du site ;
- chemins vers les dossiers, modules, icones ;

Choisissez parmi les éditeurs WYSIWYG inclus dans l'archive :
- CKeditor(3.6.3)
- TinyMCE (3.5.5)
Vous pouvez utiliser votre éditeur WYSIWYG préféré ! (ou en utiliser un autre, à votre convenance)

modules/mod_news/news_config.php
Sélectionnez
<?php
// ---------------------------------------------------------------
// MODULE des NEWS : PARAMETRES de CONFIGURATION
// ---------------------------------------------------------------

// ---------------------------------------------------------------
// CHEMINS vers les DOSSIERS
// ---------------------------------------------------------------
// ==> voir le fichier de configuration générale : config/main_config.php

// ---------------------------------------------------------------
// Base de Données : table des NEWS
// ---------------------------------------------------------------
// ==> table des NEWS en Base de Données :
if(!defined('T_NEWS_TABLE')) 			define('T_NEWS_TABLE', 			'NEWS_TAB_ARTICLES');
// ==> Création et Structure de la table : modules/mod_news/news_tableSQL.txt
// (la gestion de langues n'est pas prévue dans cette source)

// -------------------------
// ==> table de CONNEXION à l'ADMIN :
if(!defined('T_NEWS_ADM_CONNEXION')) 	define('T_NEWS_ADM_CONNEXION', 	'NEWS_ADM_CONNEXION');
// IMPORTANT : CHANGEMENT DES IDENTIFIANT et MOT DE PASSE :
// ==> Par sécurité, la modification devra se faire MANUELLEMENT directement dans la base de données
// ==> Générer un mot de passe hashé : admin/adm-createpwd.php

// ---------------------------------------------------------------
// CONFIGURATION de l'AFFICHAGE DES NEWS
// ---------------------------------------------------------------
// LISTING DES NEWS :
// ==> Taille maxi du RESUME (en nombre de caractères)
if(!defined('NEWS_RESUME_NBRECAR')) 	define('NEWS_RESUME_NBRECAR', 	120);

// ==> Résumé du Contenu (brut ou html)
//if(!defined('NEWS_RESUME_TYPE')) 		define('NEWS_RESUME_TYPE', 		'brut');	// Résumé : texte brut, sans balises html
if(!defined('NEWS_RESUME_TYPE')) 		define('NEWS_RESUME_TYPE', 		'html');	// Résumé : format html, conserve les balises html

// ==> Taille des PETITES Photos (en pixels)
if(!defined('NEWS_LARGEUR_PICTO')) 		define('NEWS_LARGEUR_PICTO', 	100);

// -------------------------
// PAGINATION :
// ==> Nombre de Colonnes (1 à 6)	-> style CSS (.newsListeColonne) : mod_news/css/news_style.css
if(!defined('NEWS_NBRE_COLONNE')) 		define('NEWS_NBRE_COLONNE', 	2);

// ==> Nombre de News à afficher par page
if(!defined('NEWS_NBRE_PARPAGE')) 		define('NEWS_NBRE_PARPAGE', 	4);	//  définir en fonction du nombre de colonnes : 3 x 4 colonnes, par exemple)

	// ==> Nombre Maxi à afficher : on ne veut prendre en compte que les xxx plus récentes (ex : les 30 dernieres)
if(!defined('NEWS_NBRE_MAXITOTAL')) 	define('NEWS_NBRE_MAXITOTAL', 	30);

// ---------------------------------------------------------------
// PARAMETRES POUR LES PHOTOS / FICHIERS
// ---------------------------------------------------------------
// ==> Choix du dossier de stockage (ces dossiers doivent être déprotégés en ecriture : chmod 777)
if(!defined('NEWS_REP_PHOTOS')) 			define('NEWS_REP_PHOTOS', 		NEWS_UPLOAD.'images/news_photos/');		// PHOTOS
if(!defined('NEWS_REP_FILES')) 			define('NEWS_REP_FILES', 		NEWS_UPLOAD.'files/news_files/');		// FICHIERS
// -------------------------
// UPLOAD : Restrictions sur les fichiers
// taille maxi des fichiers
if(!defined('NEWS_SIZEMAX_PHOTO')) 		define('NEWS_SIZEMAX_PHOTO', 	10000000);	// 10 Mo
if(!defined('NEWS_SIZEMAX_FILE')) 		define('NEWS_SIZEMAX_FILE',		10000000);	// 10 Mo

// EXTENSIONS acceptées
if(!defined('NEWS_EXTENSION_PHOTO')) 	define('NEWS_EXTENSION_PHOTO',	'jpg,jpeg,png,gif');
if(!defined('NEWS_EXTENSION_FILE')) 	define('NEWS_EXTENSION_FILE',	'pdf');

// MIME TYPES acceptés
if(!defined('NEWS_MIMETYPE_PHOTO')) 	define('NEWS_MIMETYPE_PHOTO',	'image/jpeg,image/png,image/gif');
if(!defined('NEWS_MIMETYPE_FILE')) 		define('NEWS_MIMETYPE_FILE',	'application/pdf');

// ---------------------------------------------------------------
// PARAMETRES POUR L EDITEUR WYSIWYG
// ---------------------------------------------------------------
// ==> Choix de l editeur
	if(!defined('NEWS_EDITEUR_WYSIWYG')) 	define('NEWS_EDITEUR_WYSIWYG', 		'CKeditor');		// CKeditor
//	if(!defined('NEWS_EDITEUR_WYSIWYG')) 	define('NEWS_EDITEUR_WYSIWYG', 		'TinyMCE');			// TinyMCE
//	if(!defined('NEWS_EDITEUR_WYSIWYG')) 	define('NEWS_EDITEUR_WYSIWYG', 		''); 				// rien (pour du texte brut)

// -------------------------
// SPECIAL CKeditor: 					-> http://ckeditor.com
// -------------------------
// -> Toolbar personnalisable dans : 	utilitaires/CKeditor/config.js
// -> http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Toolbar
	if(!defined('NEWS_CKeditor_TOOLBAR')) 	define('NEWS_CKeditor_TOOLBAR', 		'ToolbarArticle');	// Toolbar PERSONALISEE : Contenu Article
//	if(!defined('NEWS_CKeditor_TOOLBAR')) 	define('NEWS_CKeditor_TOOLBAR', 		'Full');			// Full
//	if(!defined('NEWS_CKeditor_TOOLBAR')) 	define('NEWS_CKeditor_TOOLBAR', 		'Basic');			// Basic
// Remarque :
// Contrairement à FCKeditor, l'Exploreur de Fichier n'est pas intégré et il est... PAYANT (CKFinder -> http://ckfinder.com)
// UNE ALTERNATIVE : KCfinder 			-> http://kcfinder.sunhater.com
// (GRATUIT, open-source) ! (contenu dans cette source !)

// -------------------------
// SPECIAL TinyMCE (3.5.5) : 			-> http://www.tinymce.com
//										-> http://www.tinymce.com/wiki.php/Installation
// 										-> http://www.tinymce.com/wiki.php/Configuration
// -------------------------
// -> Toolbar personnalisable dans : 	utilitaires/TinyMCE/jscripts/tiny_mce/config_perso.js
// Remarque :
// PROBLEME d'affichage UTF-8 dans l'éditeur : je n'ai pas trouvé (ni trop cherché !) la solution...
// ---------------------------------------------------------------
Styles CSS spécifiques à la News :
modules/mod_news/news_style.css
- stylez l'affichage de vos Nouvelles ;

3-D. Accès à la partie Administration

Authentification :
admin/index.php
formulaire d'authentification par Identifiant et Mot de Passe ;
Vérification de l'identifiant et du mot de passe :
admin/_includes/_protect_index.php
Vous pouvez choisir comment vous connecter :
- "sans base de données" : remplacer par le contenu du fichier admin/_includes/_protect_index_SANS_BDD.php ;
- "avec base de données" : remplacer par le contenu du fichier admin/_includes/_protect_index_AVEC_BDD.php ;
(dans ce cas, il faut avoir créé la table de connexion en base de données)
Image non disponible

4. Administration, Gestion des Nouvelles

4-A. Admin : Liste des News

Liste des News :
admin/adm_mod_news/news_liste.php


Pour chaque News :
- bouton "Supprimer" ;
- informations (Date, Titre de l'Article, publié...) ;
- bouton "Voir" ;
- bouton "Modifier" ;
Image non disponible

4-B. Admin : Formulaire(s) Ajouter / Modifier / Supprimer

Formulaire de gestion :
(Le choix de l'éditeur WYSIWYG appelle une page spécifique)
admin/adm_mod_news/news_formuler.php
admin/adm_mod_news/news_formulerCKeditor.php
admin/adm_mod_news/news_formulerTinyMCE.php
Formulaire de gestion (Ajouter / Modifier / Supprimer)
- Publier : Oui (affichée sur le site) ou Non (non affichée, mais conservée) ;
- Titre, Contenu (avec l'éditeur WYSIWYG choisi) ;
- photo : Ajouter / Modifier / Supprimer une photo (illustration de l'article) ;
- choix de la largeur d'affichage de la photo ;
- fichier : Ajouter / Modifier / Supprimer un fichier (joint à l'article) ;
1ère Vérification (javascript) :
(Le choix de l'éditeur WYSIWYG appelle une page spécifique)
admin/adm_mod_news/js/news_validFormulaire.js
admin/adm_mod_news/js/news_validFormulaireCKeditor.js
admin/adm_mod_news/js/news_validFormulaireTinyMCE.js
1ère Vérification (javascript), avant envoi du formulaire :
- vérification des champs obligatoires ;
- photo : vérification de l'extension (extensions acceptées) ;
- fichier : vérification de l'extension (extensions acceptées) ;
- alerte en cas d'erreur ;


Ajouter :

Image non disponible

Modifier :

Image non disponible

Supprimer :

Image non disponible

4-B1. Formulaires : news_formulerCKeditor.php (avec CKeditor)

 
Sélectionnez
<?php
// ---------------------------------------------------
// protection ADMIN - Connexion - CONFIGURATION
	include_once(dirname(__DIR__) . '/_includes/html0.php');
// ---------------------------------------------------
// ADMIN NEWS : FORMULAIRE "Ajouter"/"Modifier"/"Supprimer"
// ---------------------------------------------------
// Editeur WYSIWYG utilisé : CKeditor
	include_once(dirname(dirname(__DIR__)) . '/utilitaires/CKeditor/ckeditor.php') ;
// -----------------
	$traiter 			= '';
if (isset($_POST['traiter']) && in_array($_POST['traiter'],array('Ajouter','Modifier','Supprimer'))) {
	$traiter 			= $_POST['traiter'];
} else {
	// sinon retour a la liste
	header('location: ./news_liste.php');
	exit;
}

// -------------------------
// Ajouter
if ($traiter=='Ajouter')
{
	$newsId 			= 0;
}
// -------------------------
// Modifier / Supprimer
elseif (in_array($traiter, array('Modifier','Supprimer')))
{
	$newsId 			= intval($_POST['newsId']);
}
// -------------------------
// On récupère les infos dans la BD (ou Initialisation si Ajouter)
	include(dirname(dirname(__DIR__)) . '/'.NEWS_MOD_NEWS.'news_data_fromBD.php');
?>
<?php	include_once(dirname(__DIR__) . '/_includes/html1.php'); ?>
<title>News | <?php echo $traiter; ?> un Article</title>
<?php	include_once(dirname(__DIR__) . '/_includes/html2.php'); ?>
<h1>Administration des Articles</h1>

<div id="containerTop">
	<h2><?php echo $traiter; ?> un Article</h2>
	<!-- Retour -->
	<div id="boxBoutonTopRight">
		<a class="aLienRetour" href="./news_liste.php"><span>Retour à la Liste</span></a>
	</div>
</div>
<?php
// -------------------------
// initialisation
	$validNews 				= 0;
	$MsgValidOK 			= '';
	$MsgErreurChamps 		= '';
	$msgErreurPhoto 		= '';
	$msgErreurFile 			= '';
// -------------------------
// TRAITEMENT SI FORMULAIRE envoyé
if(isset($_POST['bt'.$traiter.'News']) && isset($_POST['codevalid']) && $_POST['codevalid']==$_SESSION['codevalid'])
{
	include_once(__DIR__ . '/_inclus/news_traiter.php');
}
// On crée un code de validation, pour éviter le rafraichissement du formulaire (F5)
// (Si "Ajouter" : éviter de copier plusieurs fois le même enregistrement)
$_SESSION['codevalid']		= rand (10000, 90000);
// -------------------------
// AFFICHAGE du RECAPITULATIF
if($validNews==1)
{
	include_once(__DIR__ . '/_inclus/news_recap.php');
}
// -------------------------
// AFFICHAGE du FORMULAIRE
else
{
?>

<?php if (in_array($traiter, array('Ajouter', 'Modifier'))) { ?>
	<!-- SCRIPT de VALIDATION du formulaire -->
	<script type="text/javascript" src="./js/news_validFormulaire<?php echo NEWS_EDITEUR_WYSIWYG; ?>.js"></script>
	<!-- Editeur WYSIWYG : CKeditor -->
	<script type="text/javascript" src="../../utilitaires/CKeditor/ckeditor.js"></script>
<?php } ?>
<!-- scripts - fin -->

<div class="containerContenu">

<?php	if ($MsgErreurChamps!='' || $msgErreurPhoto!='' || $msgErreurFile!='') { ?>
			<?php echo ($MsgErreurChamps!='')? 	'<div class="boxMsgErreur">'.$MsgErreurChamps.'</div>' : ''; ?>
			<?php echo ($msgErreurPhoto!='')? 	'<div class="boxMsgErreur">'.$msgErreurPhoto.'</div>' : ''; ?>
			<?php echo ($msgErreurFile!='')? 	'<div class="boxMsgErreur">'.$msgErreurFile.'</div>' : ''; ?>
<?php	} ?>

<!-- formulaire -->
<form method="post" enctype="multipart/form-data" action="<?php echo $_SERVER['PHP_SELF']; ?>" onsubmit="newsValidFormulaire(); return false;">
<fieldset>
	<input type="hidden" name="codevalid" value="<?php echo $_SESSION['codevalid']; ?>" />
	<input type="hidden" name="traiter" value="<?php echo $traiter; ?>" />
	<input type="hidden" name="newsId" value="<?php echo $newsId; ?>" />
	<input type="hidden" name="newsDate" value="<?php echo $newsDate; ?>" />
	<input type="hidden" name="newsPhotoAvant" value="<?php echo $newsPhotoAvant; ?>" />
	<input type="hidden" name="newsFileAvant" value="<?php echo $newsFileAvant; ?>" />

<?php // -------------------------
if (in_array($traiter, array('Ajouter', 'Modifier')))
{
?>
	<div id="containerContenuGauche">
		<h4>Article</h4>

		<p><!-- Publier ? -->
			<label><acronym title="Afficher l'Article sur le site ?">Publier</acronym> l'Article ? </label>
<?php		$Publier_Array = array(
							1	=>	'Oui',
							0	=>	'Non'
							);
			$pubAbbr_Array = array(
							1 	=>	'Oui, Publié sur le site',
							0 	=>	'Non, mais l\'Article est conservé (archivé)'
							);
			foreach ($Publier_Array as $val => $nom){
				$checked = ($newsPublier==$val)? ' checked="checked"' : '';
?>			<input class="radioInput" id="idnewsPublier<?php echo $val; ?>" name="newsPublier" type="radio" value="<?php echo $val; ?>"<?php echo $checked; ?> />
			<label class="radioLabel" for="idnewsPublier<?php echo $val; ?>"><abbr title="<?php echo $pubAbbr_Array[$val]; ?>"><?php echo $nom; ?></abbr> </label>
<?php 		} ?>
		</p>

		<p><!-- Titre -->
			<label for="idnewsTitre">Titre <abbr title="obligatoire">*</abbr>: </label>
			<input type="text" id="idnewsTitre" name="newsTitre" size="80" value="<?php echo $newsTitre; ?>" />
		</p>

		<p><!-- Contenu :  Editeur WYSIWYG CKeditor -->
			<label for="idArticleContenu">Contenu <abbr title="obligatoire">*</abbr>:</label><br />
			<textarea id="idnewsContenu" name="newsContenu" class="CKeditor"><?php echo $newsContenu; ?></textarea>
		</p>
			<script type="text/javascript">CKEDITOR.replace( 'newsContenu' );</script>

	</div>

	<div id="containerContenuDroit">
		<h4>Photo</h4>

<?php	if ($newsPhotoAvant!=''){ // remarque : EN LOCAL, fctaffichimage() nécessite un chemin relatif ?>
		<p><!-- Photo -->
			<img <?php echo fctaffichimage('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant, 150, 150); ?> alt="<?php echo $newsPhotoAvant; ?>" title="<?php echo $newsPhotoAvant; ?>" />
			<span style="float:right">
			<label class="checkboxLabel" for="idnewsPhotoDelete">Supprimer ? </label>
			<input class="checkboxInput" id="idnewsPhotoDelete" type="checkbox" name="newsPhotoDelete" value="ON" />
			</span>
		</p>
<?php	} ?>

		<p><!-- upload Photo -->
			<label for="idnewsPhoto"><?php echo ($newsPhotoAvant=='')? 'Joindre une Photo' : 'Changer de Photo'; ?> : (<?php echo NEWS_EXTENSION_PHOTO; ?>) </label><br />
			<input type="file" id="idnewsPhoto" name="newsPhoto" size="25" onchange="testExtension('idnewsPhoto','<?php echo htmlspecialchars(NEWS_EXTENSION_PHOTO); ?>');" />
		</p>
		<p id="boxnewsPhotoLargeur" style="display:none;">
			<!-- largeur Photo -->
			<label for="idnewsPhotoLargeur">Largeur (affichage) : </label>
			<select id="idnewsPhotoLargeur" name="newsPhotoLargeur" size="1">
<?php			$PhoW_array 	= array(
								100 		=> 'mini : 100px',
								200 		=> 'petit : 200px',
								300 		=> 'normal : 300px',
								450 		=> 'moyen : 450px',
								600 		=> 'maxi : 600px'
								);
				foreach ($PhoW_array as $PhoW_val => $PhoW_nom)
				{
					$PhoW_Selected = (isset($newsPhotoLargeur) && $newsPhotoLargeur==$PhoW_val)? ' selected="selected"' : '';
?>					<option value="<?php echo $PhoW_val; ?>"<?php echo $PhoW_Selected; ?>><?php echo $PhoW_nom; ?></option>
<?php 			} ?>
			</select>
		</p>

		<h4>Fichier</h4>

<?php	if ($newsFileAvant!=''){ ?>
		<p><!-- Fichier -->
			<label>Fichier :</label>
			<a href="<?php echo NEWS_ROOT.NEWS_REP_FILES.$newsFileAvant; ?>" title="<?php echo $newsFileAvant; ?>" onclick="javascript:window.open(this.href); return false;">
			<img src="<?php echo REP_ADM_ICONES; ?>PDF.png" alt="<?php echo $newsFileAvant; ?>" /></a>
			<span style="float:right">
			<label class="checkboxLabel" for="idnewsFileDelete">Supprimer ? </label>
			<input class="checkboxInput" id="idnewsFileDelete" type="checkbox" name="newsFileDelete" value="ON" />
			</span>
		</p>
<?php	} ?>

		<p><!-- upload fichier -->
			<label for="idnewsFile"><?php echo ($newsFileAvant=='')? 'Joindre un Fichier' : 'Changer de Fichier'; ?> : (<?php echo NEWS_EXTENSION_FILE; ?>)</label><br />
			<input type="file" id="idnewsFile" name="newsFile" size="25" onchange="testExtension('idnewsFile','<?php echo htmlspecialchars(NEWS_EXTENSION_FILE); ?>');" />
		</p>

		<h4>Validation</h4>

		<div id="boxValidation">
			<div class="aLienAnnuler"><a href="./news_liste.php"><span>Annuler</span></a></div>
			<button class="btValider btValider<?php echo $traiter; ?>" name="bt<?php echo $traiter; ?>News" type="submit">
			<span>Valider <?php echo $traiter; ?></span></button>
		</div>

		<div id="boxLoading"></div>

	</div>

<?php
} // -------------------------
elseif ($traiter=='Supprimer')
{
?>
	<div id="containerContenuGauche">
		<h4>Article</h4>

		<p><!-- Publier ? (oui-non) -->
			<label><acronym title="Afficher l'Article sur le site ?">Publier</acronym> : </label>
			<?php if($newsPublier==1) { ?>Oui<?php } elseif($newsPublier==0) { ?>Non<?php } ?>
		</p>

		<p><!-- Titre -->
			<label>Titre : </label>
			<b><?php echo $newsTitre; ?></b>
		</p>
	</div>

	<div id="containerContenuDroit">
<?php	if ($newsPhotoAvant!=''){ // remarque : EN LOCAL, fctaffichimage() nécessite un chemin relatif ?>
		<p><!-- Photo -->
			<label style="min-width:30px;">
			<img <?php echo fctaffichimage('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant, 24, 24); ?> alt="<?php echo $newsPhotoAvant; ?>" title="<?php echo $newsPhotoAvant; ?>" />
			</label>
			(la Photo sera aussi supprimée)
		</p>
<?php	} ?>

<?php	if ($newsFileAvant!=''){ ?>
		<p><!-- Fichier -->
			<a href="<?php echo NEWS_ROOT.NEWS_REP_FILES.$newsFileAvant; ?>" onclick="javascript:window.open(this.href); return false;">
			<label style="min-width:30px;"><img src="<?php echo REP_ADM_ICONES; ?>PDF.png" alt="<?php echo $newsFileAvant; ?>" /></a></label>
			(le fichier sera aussi supprimé)
		</p>
<?php	} ?>

		<h4>Validation</h4>

		<div id="boxValidation">
			<div class="aLienAnnuler"><a href="./news_liste.php"><span>Annuler</span></a></div>
			<button class="btValider btValider<?php echo $traiter; ?>" name="bt<?php echo $traiter; ?>News" type="submit">
			<span>Valider <?php echo $traiter; ?></span></button>
		</div>

		<div id="boxLoading"></div>

	</div>

<?php
}
?>
</fieldset>
</form>
</div>
<?php
} // fin AFFICHAGE du FORMULAIRE
?>
<?php	include_once(dirname(__DIR__) . '/_includes/html3.php'); ?>

4-B2. Vérification JavaScript : js/news_validFormulaireCKeditor.js (avec CKeditor)

 
Sélectionnez

/* NEWS - VALIDATION DU FORMULAIRE */

		function newsValidFormulaire() {
			var error 				= '';		
			var setfocus 			= 0;
			var idnewsTitre			= document.getElementById('idnewsTitre');
			var idnewsContenu		= document.getElementById('idnewsContenu');
			var idnewsContenuValue 	= CKEDITOR.instances.idnewsContenu.getData();		// Spécial CKEditor
		
			/* Champs obligatoires */
			if(idnewsTitre.value=='') {
				error += '- Titre de l\'Article\n';
				if(setfocus==0) { idnewsTitre.focus(); }
				setfocus += 1;
			}

			if(idnewsContenuValue=='') {	// Spécial CKEditor
				error += '- Contenu de l\'Article\n';
				if(setfocus==0) { idnewsContenu.focus(); }
				setfocus += 1;
			}

			if(error!='') {
				if(setfocus==1) { alert('Veuillez remplir le champ suivant :\n\n' + error); }
				else { alert('Veuillez remplir les champs suivants :\n\n' + error); }
				return false;
			} else {
				/* affichage d'une barre de progression */
				document.getElementById('boxValidation').style.display = 'none';
				document.getElementById('boxLoading').style.display = 'block';
				/* on envoie le formulaire */
				document.submit();
				return true;
			}
		};

		/* PHOTO/FILE : vérification extension */
		function testExtension(iddiv, extensionsok) {
			var iddiv;
			var valeur		= document.getElementById(iddiv).value.toLowerCase();
			var extensionsok; 
			var chainearray = valeur.split('.');
			var extension 	= chainearray[chainearray.length-1]; /* extension du fichier */
			if(extensionsok.indexOf(extension)==-1) { /* extension pas ok */
				document.getElementById(iddiv).value = '';
				alert('Erreur : ce fichier n\'est pas valide !\n\nExtensions acceptées : ' + extensionsok);
				document.getElementById('boxnewsPhotoLargeur').style.display = 'none';
				return false;
			} else {
				document.getElementById('boxnewsPhotoLargeur').style.display = 'block';
				return true;
			}
		};

4-C. Admin : Traitement(s) Ajouter / Modifier / Supprimer

2ème Vérification (PHP) + Traitement :
admin/adm_mod_news/_inclus/news_traiter.php


Les traitements (Ajouter / Modifier / Supprimer) sont effectués dans le même fichier :
- récupération des données transmises ;
- 2ème Vérification (PHP) : gestion d'erreurs (entêtes interdits, champs obligatoires) ;
- enregistrement en base de données (INSERT, UPDATE ou DELETE) ;
- appel du traitement de la photo et du fichier joint ;
Traitement de la photo :
admin/adm_mod_news/_inclus/news_traiter_photo.php

- upload : gestion d'erreurs (restrictions, extension, type MIME) ;
- redimensionnement automatique (si nécessaire) ;
- enregistrement physique (ou suppression) de la photo dans le dossier upload/images/news_photos ;
- enregistrement de l'URL (ou suppression) de la photo en base de données ;
Traitement du fichier :
admin/adm_mod_news/_inclus/news_traiter_file.php
- upload : gestion d'erreurs (restrictions, extension, type MIME) ;
- enregistrement physique (ou suppression) de la photo dans le dossier upload/images/news_photos ;
- enregistrement de l'URL (ou suppression) de la photo en base de données ;
Récapitulatif :
admin/adm_mod_news/_inclus/news_recap.php
- récapitulatif, réaffichage de la News après traitement ;
- bouton "Corriger ?" ;

4-C1. Traitement principal : news_traiter.php

 
Sélectionnez
<?php
// ---------------------------------------------------
// NEWS : TRAITEMENT des donnees (newsTitre, newsContenu)
// ---------------------------------------------------
$traiter = '';
if (isset($_POST['traiter']) && ($_POST['traiter']!='Ajouter' || $_POST['traiter']!='Modifier' || $_POST['traiter']!='Supprimer')){
	$traiter = $_POST['traiter'];
} else {
	// sinon retour a la liste
	header('location: ./news_liste.php');
	exit;
}
// --------------------
// initialisation
	$MsgValidAjouter 		= 'L\'Article a été ajouté.';
	$MsgValidModifier 		= 'L\'Article a été modifié.';
	$MsgValidSupprimer 		= 'L\'Article a été supprimé.';

// -------------------------
if (in_array($traiter,array('Ajouter','Modifier')))
{
	// -----------------------------------------
	// 1- RECUPERATION DES DONNEES DU FORMULAIRE
	// -----------------------------------------
	$newsId 				= (isset($_POST['newsId']))?			intval($_POST['newsId']) : 0;
	$newsTitre 				= (isset($_POST['newsTitre']))?			formatage_from_post($_POST['newsTitre']) : '';
	$newsContenu 			= (isset($_POST['newsContenu']))?		formatage_from_textarea($_POST['newsContenu']) : ''; 	// textarea
	$newsPublier 			= (isset($_POST['newsPublier']))?		intval($_POST['newsPublier']) : 1; // Oui
	$newsDate 				= (isset($_POST['newsDate']))?			intval($_POST['newsDate']) : time(); // date du jour par défaut

	// -----------------------------------------
	// 2- GESTION des ERREURS
	// -----------------------------------------
	// Expression régulière pour vérifier qu'aucun en-tête n'est inséré dans les champs
	$regex_head = '/[\n\r]/';
	// pas de header dans les champs text */
	if (preg_match($regex_head, $newsTitre)) {
		$MsgErreurChamps 	.= 'Entêtes interdites dans les champs du formulaire !<br />';
		$validNews 			= 2;
	}
	// ---------------------
	// champs obligatoires
	$champ_obligatoire = array();
	if ($newsTitre=='') {			$validNews = 2;		$champ_obligatoire[] = 'Titre'; }
	if ($newsContenu=='') {			$validNews = 2;		$champ_obligatoire[] = 'Contenu'; }
	if($validNews==2 && count($champ_obligatoire)>0) {
		$MsgErreurChamps 	.= 'Remplissez tous les champs obligatoires :<br /><b>'.implode('</b>, <b>',$champ_obligatoire).'</b><br />';
	}
	// ---------------------
	if ($validNews!=2) {
		$validNews 			= 1;
		// -----------------
	}

	// -----------------------------------------
	// 3- ENREGISTREMENT
	// -----------------------------------------
	// Ajouter
	if ($validNews==1 && $traiter=='Ajouter')
	{
		// INSERT : nouvelle entree dans la table
		// on met la date du jour (timestamp) : time()
		$insert_query 		= "INSERT INTO ".T_NEWS_TABLE.
							" (".
							" news_titre, ".
							" news_contenu, ".
							" news_publier, ".
							" news_date ". // (pas de virgule)
							") VALUES (".
							" :newsTitre, ".
							" :newsContenu, ".
							" :newsPublier, ".
							" :newsDate". // (pas de virgule)
							");";
	  try {
		$pdo_insert 		= $pdo->prepare($insert_query);
		$pdo_insert->bindValue(':newsTitre', 		$newsTitre,				PDO::PARAM_STR);
		$pdo_insert->bindValue(':newsContenu', 		$newsContenu,			PDO::PARAM_STR);
		$pdo_insert->bindValue(':newsPublier', 		$newsPublier,			PDO::PARAM_INT);
		$pdo_insert->bindValue(':newsDate', 		$newsDate,				PDO::PARAM_INT);
		$pdo_insert->execute();
		// -----------------
		$MsgValidOK 		= $MsgValidAjouter;
		$traiter 			= 'Modifier';	// Ajouter -> Modifier
		// -----------------
		// recuperation de newsId en selectionnant LA DERNIERE fiche cree
		$newsId 			= $pdo->lastInsertId('news_id');
	  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
	} // fin Ajouter

	// -----------------------------------------
	// Modifier
	elseif ($validNews==1 && $traiter=='Modifier')
	{
		// on ne change pas la date
		// UPDATE de la fiche :
		$update_query 		= "UPDATE ".T_NEWS_TABLE." SET ".
							" news_titre 			= :newsTitre, ".
							" news_contenu 			= :newsContenu, ".
							" news_publier 			= :newsPublier, ".
							" news_date 			= :newsDate ". // (pas de virgule)
							" WHERE news_id 		= :newsId;";
	  try {
		$pdo_update 		= $pdo->prepare($update_query);
		$pdo_update->bindValue(':newsTitre', 		$newsTitre,				PDO::PARAM_STR);
		$pdo_update->bindValue(':newsContenu', 		$newsContenu,			PDO::PARAM_STR);
		$pdo_update->bindValue(':newsPublier', 		$newsPublier,			PDO::PARAM_INT);
		$pdo_update->bindValue(':newsDate', 		$newsDate,				PDO::PARAM_INT);
		$pdo_update->bindValue(':newsId', 			$newsId,				PDO::PARAM_INT);
		$pdo_update->execute();
		// -----------------
		$MsgValidOK 		= $MsgValidModifier;
	  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
	} // fin Modifier

	// -----------------------------------------
	// Ajouter ou Modifier
	// -----------------------------------------
	if ($validNews==1 && in_array($traiter, array('Ajouter', 'Modifier')))
	{
		// ----------------------
		// traitement Photo ?
		include(__DIR__ . '/news_traiter_photo.php');
		// ----------------------
		// traitement Fichier ?
		include(__DIR__ . '/news_traiter_file.php');
	} // fin Ajouter/Modifier
}
// -------------------------
// Traitement : Supprimer
// -------------------------
elseif ($traiter == 'Supprimer')
{
	$newsId 				= (isset($_POST['newsId']))?				intval($_POST['newsId']) : 0;
	$newsPhotoAvant 		= (isset($_POST['newsPhotoAvant']))? 		formatage_from_post($_POST['newsPhotoAvant']) : '';
	$newsFileAvant 			= (isset($_POST['newsFileAvant']))? 		formatage_from_post($_POST['newsFileAvant']) : '';
	// ----------------------
	// Suppression de la Fiche dans la BD
	$delete_query 			= "DELETE FROM ".T_NEWS_TABLE." ".
							" WHERE news_id = :newsId;";
 	  try {
		$pdo_delete 		= $pdo->prepare($delete_query);
		$pdo_delete->bindValue(':newsId', 		$newsId,		PDO::PARAM_INT);
		$pdo_delete->execute();
		// -----------------
		$MsgValidOK 		= $MsgValidSupprimer;
		$validNews			= 1;
	  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
	// ----------------------
	// Suppression de la Photo du dossier
	if($newsPhotoAvant!='' && file_exists('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant)) {
		unlink('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant);
	}
	// ----------------------
	// Suppression du Fichier du dossier
	if($newsFileAvant!='' && file_exists('../../'.NEWS_REP_FILES.$newsFileAvant)) {
		unlink('../../'.NEWS_REP_FILES.$newsFileAvant);
	}
	// ----------------------
}
// -------------------------
unset($_POST);

4-C2. Traitement Photo : news_traiter_photo.php

 
Sélectionnez
<?php
// ---------------------------------------------------
// ADMIN NEWS : TRAITEMENT des photos
// ---------------------------------------------------
// RECUPERATION DES DONNEES DU FORMULAIRE
// photo
	$newsPhotoAvant 		= (isset($_POST['newsPhotoAvant']))? 		formatage_from_post($_POST['newsPhotoAvant']) : '';
	$newsPhotoDelete 		= (isset($_POST['newsPhotoDelete']))? 		formatage_from_post($_POST['newsPhotoDelete']) : '';
	$newsPhotoLargeur 		= (isset($_POST['newsPhotoLargeur']))? 		formatage_from_post($_POST['newsPhotoLargeur']) : '';

// -----------------
// Gestion des photos supprimees
if ($newsPhotoAvant!='' && $newsPhotoDelete=='ON')
{
	// Suppression de l'ancienne Photo
	if(file_exists('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant)) {
		unlink('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant);
	}
	// -----------------
	// Suppression dans la base de donnees par UPDATE
	$update_query 			= "UPDATE ".T_NEWS_TABLE." ".
							" SET news_photo 	= '' ".
							" WHERE news_id 	= :newsId;";
  try {
	$pdo_update 			= $pdo->prepare($update_query);
	$pdo_update->bindValue(':newsId', 		$newsId,		PDO::PARAM_INT);
	$pdo_update->execute();
  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
	// -----------------
}

// ----------------------------------
// VERIFICATION / TRAITEMENT de la photo si uploadee
// ----------------------------------
$msgErreurPhoto 			= ''; 	// message d erreur
$traiterPhotoOK 			= true; // (par defaut)

if(isset($_FILES['newsPhoto']) && $_FILES['newsPhoto']['size'] > 0)
{
	// -------------------------------------
	// extension du fichier uploadé (en minuscule)
	$file_Extension 		= strtolower(pathinfo($_FILES['newsPhoto']['name'],PATHINFO_EXTENSION));

	// Type MIME réel du fichier (important : évite les fichiers NON valides, dont l'extension a été renommée)
//	$finfo 					= new finfo(FILEINFO_MIME_TYPE, NULL); // Retourne le type mime
//	$file_MimeType 			= $finfo->file($_FILES['newsPhoto']['tmp_name']);

	// (alternative, si la CLASS finfo n'est pas supportée)
	$finfo 					= finfo_open(FILEINFO_MIME_TYPE); // Retourne le type mime à la extension mimetype
	$file_MimeType 			= finfo_file($finfo, $_FILES['newsPhoto']['tmp_name']);
	finfo_close($finfo);

	// -------------------------------------
	// GESTION DES ERREURS
	// -------------------------------------
	// on vérifie les RESTRICTIONS sur les fichiers
	if (UPLOAD_ERR_OK<>0 && UPLOAD_ERR_FORM_SIZE==2) {
		$msgErreurPhoto 	.= 'Taille de fichier trop important ('.NEWS_SIZEMAX_PHOTO.' octets)<br />';
		$traiterPhotoOK 	= false;
	}
	// -----------------
	// on vérifie la TAILLE MAXI
	elseif ($_FILES['newsPhoto']['size'] > NEWS_SIZEMAX_PHOTO) {
		$msgErreurPhoto 	.= 'Taille de fichier supérieure à la taille maxi autorisée ('.NEWS_SIZEMAX_PHOTO.' octets)<br />';
		$traiterPhotoOK 	= false;
	}
	// -----------------
	// on vérifie l'EXTENSION
	elseif(!in_array($file_Extension, explode(',', constant('NEWS_EXTENSION_PHOTO')))) {
		$msgErreurPhoto 	.= 'L\'extension ne correspond pas (Extensions acceptées  : <b>'.constant('NEWS_EXTENSION_PHOTO').'</b>)<br />';
		if(in_array($file_MimeType, explode(',', constant('NEWS_MIMETYPE_PHOTO')))) {
		  $msgErreurPhoto 	.= '<b>Attention</b> : Ce fichier est peut-être corrompu !<br />';
		  $msgErreurPhoto 	.= 'L\'extension ne correspond pas au type MIME !<br />';
		}
		$traiterPhotoOK 	= false;
	}
	// -----------------
	// on vérifie le TYPE MIME
	elseif(!in_array($file_MimeType, explode(',', constant('NEWS_MIMETYPE_PHOTO')))) {
		$msgErreurPhoto 	.= 'Le type MIME ne correspond pas (Extensions acceptées  : <b>'.constant('NEWS_EXTENSION_PHOTO').'</b>)<br />';
		if(in_array($file_Extension, explode(',', constant('NEWS_EXTENSION_PHOTO')))) {
		  $msgErreurPhoto 	.= '<b>Attention</b> : Ce fichier est peut-être corrompu !<br />';
		  $msgErreurPhoto 	.= 'L\'extension ne correspond pas au type MIME !<br />';
		}
		$traiterPhotoOK 	= false;
	}
	// -----------------
	if ($traiterPhotoOK===false) {
		$msgErreurPhoto 	= '<b>Erreur (Photo)</b> :<br />'.$msgErreurPhoto.'Impossible d\'enregistrer le fichier.';
	}
	// -------------------------------------
	// si pas d'erreur : TRAITEMENT
	// -------------------------------------
	if ($traiterPhotoOK===true)
	{
		// --------------------
		// enregistement de la PHOTO sous forme id_nom-image(.jpg, ...)
		// NB : id etant unique (auto-increment), cela rend le nom de la photo unique
		$file_Upload 		= $newsId.'_'.$_FILES['newsPhoto']['name'];
		$file_Upload 		= formatage_nom_fichier($file_Upload); // remplacement des caracteres speciaux + tout en minuscules
		$file_Upload 		= str_replace('.jpeg','.jpg',$file_Upload); // on remplace aussi .jpeg par .jpg
		// --------------------
		// enregistrement de la photo dans le dossier
		$temp = $_FILES['newsPhoto']['tmp_name'];
		move_uploaded_file($temp, '../../'.NEWS_REP_PHOTOS.$file_Upload);
		// --------------------
		// REDIMENSIONNEMENT et SAUVEGARDE de la PHOTO (si necessaire)
		// ecraser (remplacer) la photo (meme rep, meme nom)
		$redimPHOTOOK 		= fctredimimage($newsPhotoLargeur,0,'','','../../'.NEWS_REP_PHOTOS,$file_Upload);
		// --------------------
		// SUPPRESSION des ANCIENNES PHOTOS (si necessaire) dans le dossier
		if ($newsPhotoAvant!='' && $newsPhotoAvant!=$file_Upload)
		{
			if(file_exists('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant)) {
				unlink('../../'.NEWS_REP_PHOTOS.$newsPhotoAvant);
			}
		}
		// -----------------
		// enregistrement du NOM dans la base de donnees par UPDATE
		$update_query 		= "UPDATE ".T_NEWS_TABLE." SET ".
							" news_photo 			= :file_Upload, ".
							" news_photo_largeur	= :newsPhotoLargeur ".
							" WHERE news_id 		= :newsId;";
	  try {
		$pdo_update 		= $pdo->prepare($update_query);
		$pdo_update->bindValue(':file_Upload', 		$file_Upload,		PDO::PARAM_STR);
		$pdo_update->bindValue(':newsPhotoLargeur', $newsPhotoLargeur,	PDO::PARAM_STR);
		$pdo_update->bindValue(':newsId', 			$newsId,			PDO::PARAM_INT);
		$pdo_update->execute();
	  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
		// -----------------
	}

} // fin TRAITEMENT PHOTO
// ---------------------------------------------------

4-C3. Traitement Fichier : news_traiter_file.php

 
Sélectionnez
<?php
// © Jérome Réaux : http://j-reaux.developpez.com - http://www.jerome-reaux-creations.fr
// ---------------------------------------------------
// ADMIN : ARTICLES : TRAITEMENT du FICHIER
// ---------------------------------------------------
// RECUPERATION DES DONNEES DU FORMULAIRE
// FICHIER joint
	$newsFileAvant 			= (isset($_POST['newsFileAvant']))? 		formatage_from_post($_POST['newsFileAvant']) : '';
	$newsFileDelete 		= (isset($_POST['newsFileDelete']))? 		formatage_from_post($_POST['newsFileDelete']) : '';

	// -----------------
// Gestion des fichiers supprimes
if ($newsFileAvant!='' && $newsFileDelete=='ON')
{
	// Suppression de l'ancien FICHIER
	if(file_exists('../../'.NEWS_REP_FILES.$newsFileAvant)) {
		unlink('../../'.NEWS_REP_FILES.$newsFileAvant);
	}
	// -----------------
	// Suppression dans la base de donnees par UPDATE
	$update_query 			= "UPDATE ".T_NEWS_TABLE." ".
							" SET news_file 	= '' ".
							" WHERE news_id 	= :newsId;";
  try {
	$pdo_update 			= $pdo->prepare($update_query);
	$pdo_update->bindValue(':newsId', 		$newsId,		PDO::PARAM_INT);
	$pdo_update->execute();
  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
	// -----------------
}

// ----------------------------------
// VERIFICATION / TRAITEMENT de la photo si uploadee
// ----------------------------------
$msgErreurFile 				= ''; // message d erreur
$traiterFilerOK 			= true; // (par defaut)

// -----------------
if(isset($_FILES['newsFile']) && $_FILES['newsFile']['size'] > 0)
{
	// -------------------------------------
	// extension du fichier uploadé (en minuscule)
	$file_Extension 		= strtolower(pathinfo($_FILES['newsFile']['name'],PATHINFO_EXTENSION));

	// Type MIME réel du fichier (important : évite les fichiers NON valides, dont l'extension a été renommée)
//	$finfo 					= new finfo(FILEINFO_MIME_TYPE, NULL); // Retourne le type mime
//	$file_MimeType 			= $finfo->file($_FILES['newsFile']['tmp_name']);

	// (alternative, si la CLASS finfo n'est pas supportée)
	$finfo 					= finfo_open(FILEINFO_MIME_TYPE); // Retourne le type mime à la extension mimetype
	$file_MimeType 			= finfo_file($finfo, $_FILES['newsFile']['tmp_name']);
	finfo_close($finfo);

	// -------------------------------------
	// GESTION DES ERREURS
	// -------------------------------------
	// on vérifie les RESTRICTIONS sur les fichiers
	if (UPLOAD_ERR_OK<>0 && UPLOAD_ERR_FORM_SIZE==2) {
		$msgErreurFile 		.= 'Taille du fichier trop importante ('.NEWS_SIZEMAX_FILE.' octets)<br />';
		$traiterFilerOK 	= false;
	}
	// -----------------
	// on vérifie la TAILLE MAXI
	elseif ($_FILES['newsFile']['size'] > NEWS_SIZEMAX_FILE) {
		$msgErreurFile 		.= 'Taille de fichier supérieure à la taille maxi autorisée ('.NEWS_SIZEMAX_FILE.' octets)<br />';
		$traiterFilerOK 	= false;
	}
	// -----------------
	// on vérifie l'EXTENSION
	elseif(!in_array($file_Extension, explode(',', constant('NEWS_EXTENSION_FILE')))) {
		$msgErreurFile 		.= 'L\'extension ne correspond pas (Extensions acceptées  : <b>'.constant('NEWS_EXTENSION_FILE').'</b>)<br />';
		if(in_array($file_MimeType, explode(',', constant('NEWS_MIMETYPE_FILE')))) {
		  $msgErreurFile 	.= '<b>Attention</b> : Ce fichier est peut-être corrompu !<br />';
		  $msgErreurFile 	.= 'L\'extension ne correspond pas au type MIME !<br />';
		}
		$traiterFilerOK 	= false;
	}
	// -----------------
	// on vérifie le TYPE MIME
	elseif(!in_array($file_MimeType, explode(',', constant('NEWS_MIMETYPE_FILE')))) {
		$msgErreurFile 		.= 'Le type MIME ne correspond pas (Extensions acceptées  : <b>'.constant('NEWS_EXTENSION_FILE').'</b>)<br />';
		if(in_array($file_Extension, explode(',', constant('NEWS_EXTENSION_FILE')))) {
		  $msgErreurFile 	.= '<b>Attention</b> : Ce fichier est peut-être corrompu !<br />';
		  $msgErreurFile 	.= 'L\'extension ne correspond pas au type MIME !<br />';
		}
		$traiterFilerOK 	= false;
	}
	// -----------------
	if ($traiterFilerOK===false) {
		$msgErreurFile 	= '<b>Erreur (Fichier)</b> :<br />'.$msgErreurFile.'Impossible d\'enregistrer le fichier.';
	}
	// -------------------------------------
	// si pas d'erreur : TRAITEMENT
	// -------------------------------------
	if ($traiterFilerOK===true)
	{
		// --------------------
		$file_Upload = '';
		// enregistement du FICHIER sous forme id-nom-fichier.pdf
		// NB : id etant unique (auto-increment), cela rend le nom du fichier unique
		$file_Upload 		= $newsId.'-'.$_FILES['newsFile']['name'];
		$file_Upload 		= formatage_nom_fichier($file_Upload);	// remplacement des caracteres speciaux + tout en minuscules
		// --------------------
		// enregistrement du FICHIER dans le dossier
		$temp = $_FILES['newsFile']['tmp_name'];
		move_uploaded_file($temp, '../../'.NEWS_REP_FILES.$file_Upload);
		// --------------------
		// SUPPRESSION de l ANCIENNE fiche PDF (si necessaire)
		if ($newsFileAvant!='' && $newsFileAvant!=$file_Upload)
		{
			if(file_exists('../../'.NEWS_REP_FILES.$newsFileAvant)) {
				unlink('../../'.NEWS_REP_FILES.$newsFileAvant);
			}
		}
		// -----------------
		// enregistrement du NOM dans la base de donnees par UPDATE
		$update_query 		= "UPDATE ".T_NEWS_TABLE." SET ".
							" news_file 			= :file_Upload ".
							" WHERE news_id 		= :newsId;";
	  try {
		$pdo_update 		= $pdo->prepare($update_query);
		$pdo_update->bindValue(':file_Upload', 		$file_Upload,		PDO::PARAM_STR);
		$pdo_update->bindValue(':newsId', 			$newsId,			PDO::PARAM_INT);
		$pdo_update->execute();
	  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
		// -----------------
	}

} // fin TRAITEMENT FICHIER
// ---------------------------------------------------

4-C4. Vérification du Type Mime : la Class finfo / Fonctions Fileinfo

finfo_file / finfo::file n'est disponible qu'à partir de : PHP >= 5.3.0, PECL fileinfo >= 0.1.0.

On vérifie le Type MIME réel du fichier (important : évite les fichiers NON valides, dont l'extension a pu être renommée, manuellement).
2 alternatives sont proposées dans les fichiers (news_traiter_photo.php et news_traiter_file.php).

Néanmoins, si la Class finfo n'est pas supportée, vous pouvez toujours vous passer du test de Type Mime en commentant les lignes concernées.
Ici :

 
Sélectionnez
<?php
			// Type MIME réel du fichier (important : évite les fichiers NON valides, dont l'extension a été renommée)
//	$finfo 					= new finfo(FILEINFO_MIME_TYPE, NULL); // Retourne le type mime
//	$file_MimeType 			= $finfo->file($_FILES['newsPhoto']['tmp_name']);

	// (alternative, si la CLASS finfo n'est pas supportée)
//	$finfo 					= finfo_open(FILEINFO_MIME_TYPE); // Retourne le type mime à la extension mimetype
//	$file_MimeType 			= finfo_file($finfo, $_FILES['newsPhoto']['tmp_name']);
//	finfo_close($finfo);
?>

Et là :

 
Sélectionnez
<?php
	// -----------------
	// on vérifie l'EXTENSION
	elseif(!in_array($file_Extension, explode(',', constant('FILE_EXTENSION_PHOTO')))) {
		$msgErreurPhoto 	.= 'L\'extension ne correspond pas (Extensions acceptées  : <b>'.constant('FILE_EXTENSION_PHOTO').'</b>)<br />';
//		if(in_array($file_MimeType, explode(',', constant('FILE_MIMETYPE_PHOTO')))) {
//		  $msgErreurPhoto 	.= '<b>Attention</b> : Ce fichier est peut-être corrompu !<br />';
//		  $msgErreurPhoto 	.= 'L\'extension ne correspond pas au type MIME !<br />';
//		}
		$traiterPhotoOK 	= false;
	}
	// -----------------
	// on vérifie le TYPE MIME
//	elseif(!in_array($file_MimeType, explode(',', constant('FILE_MIMETYPE_PHOTO')))) {
//		$msgErreurPhoto 	.= 'Le type MIME ne correspond pas (Extensions acceptées  : <b>'.constant('FILE_EXTENSION_PHOTO').'</b>)<br />';
//		if(in_array($file_Extension, explode(',', constant('FILE_EXTENSION_PHOTO')))) {
//		  $msgErreurPhoto 	.= '<b>Attention</b> : Ce fichier est peut-être corrompu !<br />';
//		  $msgErreurPhoto 	.= 'L\'extension ne correspond pas au type MIME !<br />';
//		}
//		$traiterPhotoOK 	= false;
//	}
?>

Ne pas utiliser :
- mime_content_type() est obsolète !
- $_FILES['image']['type'] ne fournit que le type apparent ! Ne pas lui faire confiance (l'extension du fichier a pu être modifiée manuellement)

4-D. Admin : Voir la News

Fiche de la News :
admin/adm_mod_news/news_fiche.php
- prévisualisation de la News ;
- publication : oui / non ;
- bouton "Corriger ?" ;
Image non disponible

5. Intégration dans votre le site

5-A. Site : Listing des Nouvelles

Site: listing des News :
modules/mod_news/news_liste_colonne.php
- affichage de la liste des News, selon la configuration (nombre de colonnes,...) ;
- pagination automatique ;
- pour chaque News : lien "Voir la Fiche" ;


- Soit avec résumé "brut" : le résumé est affiché sans formatage ;
- soit avec résumé "HTML" : le résumé est affiché formaté, en conservant la mise en forme html.
- Affichage sur une, deux, plusieurs colonnes.

Page d'exemple : index_news_liste.php.
-> A intégrer dans la page de votre site :

 
Sélectionnez
<?php 
// ---------------------------------------------------
// LISTING des News -> indiquez le chemin correct
	include(__DIR__.'/modules/mod_news/news_liste_colonne.php');
// ---------------------------------------------------
?>
Image non disponible

modules/mod_news/news_liste_colonne.php

 
Sélectionnez
<?php
<?php
// © Jérome Réaux : http://j-reaux.developpez.com - http://www.jerome-reaux-creations.fr
// ---------------------------------------------------
// Configuration principale
	require_once(dirname(dirname(__DIR__)) . '/config/main_config.php');
// Fonctions nécessaires + Connexion à la BdD PDO
	require_once(dirname(dirname(__DIR__)) . '/'.NEWS_FONCTIONS.'fct_toutes_fonctions_necessaires.php');
// Configuration des News
	require_once(__DIR__ . '/news_config.php');
	require_once(__DIR__ . '/news_fonctions.php');
// ---------------------------------------------------
// On récupère (via l'URL) le numéro de la page à afficher
	$newsNumPage	= (isset($_GET['pg']))? intval($_GET['pg']) : 1; // page 1 par défaut
// Affichage d un RESUME des News :  Petite photo + titre + date + résumé du contenu + lien [suite]
	news_affiche_liste_colonne($newsNumPage);
// ---------------------------------------------------

5-B. Site : Fiche de la Nouvelle

Site: fiche de la News :
modules/mod_news/news_fiche.php
- affichage de la fiche complète de la News ;
- lien "Retour à la liste" ;

Page d'exemple : index_news_fiche.php.
-> A intégrer dans la page de votre site :

 
Sélectionnez
	<div id="containerListing">
<?php 
// ---------------------------------------------------
// FICHE de la News -> indiquez le chemin correct
	include(__DIR__.'/modules/mod_news/news_fiche.php');
// ---------------------------------------------------
?>
	</div> 

	<div id="LienRetourListe">
		<a href="<?php echo (isset($_SERVER['HTTP_REFERER']))? $_SERVER['HTTP_REFERER'] : './index.php'; ?>"><span>Retour à la Liste des Articles</span></a>
	</div>
Image non disponible

5-C. Site : Configuration

Important : vous devez définir l'URL de la page "fiche de la News" dans : config/main_config.php :

 
Sélectionnez
// ---------------------------------------------------------------
// FICHE de la News 			=> INDIQUEZ LE CHEMIN CORRECT !
if(!defined('NEWS_PATH_FICHE')) 	define('NEWS_PATH_FICHE', 	'./index_news_fiche.php');	// demo
//if(!defined('NEWS_PATH_FICHE')) 	define('NEWS_PATH_FICHE', 	'http://www.nom-du-site.com/votre-news-fiche.php');  // EN PRODUCTION : chemin absolu du fichier contenant la FICHE de la news

5-D. Site : style CSS

Vous pouvez appliquer votre propre style CSS dans : mod_news/css/news_style.css.

6. Fonctions utiles

6-A. Fonctions spécifiques du module de Nouvelles

Récupération des informations en base de données :
modules/mod_news/news_data_fromBD.php
- requête des champs de la News en base de données ;
- ou initialisation des données (Ajouter) ;
Fonctions spécifiques des News :
modules/mod_news/news_fonctions.php
- fonction news_affiche_fiche() ;
- fonction news_affiche_fiche_resume_colonne() ;
- fonction news_affiche_liste_colonne() ;
- fonction news_pagination_pages() ;


Remarque : voici les fonctions pour la Version 5 (PDO).
Pour la Version 4 (MYSQL) : se reporter à l'archive correspondante.

6-A1. Fonction : news_affiche_fiche()

 
Sélectionnez
<?php
// ---------------------------------------------------
// 1a/ FONCTION : FICHE de la News (News seule)
// ---------------------------------------------------
function news_affiche_fiche($newsId)
{
	if(is_numeric($newsId) && $newsId>0)
	{
		// -------------------------
		global $pdo;
		// -------------------------
		// On recupere les infos dans la BD
		require(__DIR__ . '/news_data_fromBD.php');
		// -------------------------
?>
		<div class="newsListe">
			<div class="newsFicheEntete">
				<h4 class="newsFicheTitre"><?php echo $newsTitre; ?></h4>
				<span class="newsFicheDate"> le <?php echo date('d/m/Y à H\hi', $newsDate); ?></span>
			</div>

			<div class="newsFicheContenu">
<?php		if ($newsPhoto != '') { ?>
				<img class="newsFichePhoto" src="<?php echo NEWS_ROOT.NEWS_REP_PHOTOS.$newsPhoto; ?>" alt="" />
<?php		} ?>

				<?php echo $newsContenu; ?>

<?php		if($newsFile != '') { ?>
				<a class="newsFicheFile" href="<?php echo NEWS_ROOT.NEWS_REP_FILES.$newsFile; ?>" onclick="javascript:window.open(this.href); return false;">
				<span>Voir le Fichier joint</span></a>
<?php		} ?>
			</div>
		</div>
<?php
	} else {
		echo 'Mauvais identifiant de News';
	}
};
// ---------------------------------------------------

6-A2. Fonction : news_affiche_fiche_resume_colonne()

 
Sélectionnez
<?php
// ---------------------------------------------------
// 1b/ FONCTION : FICHE de la News (LISTE sur plusieurs colonnes)
// Avec picto, résumé du contenu et lien vers la fiche de l'Article
// ---------------------------------------------------
function news_affiche_fiche_resume_colonne($newsId)
{
	if(is_numeric($newsId) && $newsId>0)
	{
		// -------------------------
		global $pdo;
		// -------------------------
		// On recupere les infos dans la BD
		require(__DIR__ . '/news_data_fromBD.php');
		// -------------------------
		// Nombre de colonnes : 1 à 6 (voir le style CSS : .newsListeColonne)
		$NbreCol	= ( NEWS_NBRE_COLONNE>0 && NEWS_NBRE_COLONNE<7 )? NEWS_NBRE_COLONNE : '';
?>
		<div class="newsListe newsListeColonne<?php echo $NbreCol; ?>">
			<div class="newsListeEntete">
				<h4 class="newsListeTitre"><?php echo $newsTitre; ?></h4>
				<span class="newsListeDate"> le <?php echo date('d/m/Y à H\hi', $newsDate); ?></span>
			</div>

			<div class="newsListeContenu">
<?php		if ($newsPhoto != '') { ?>
				<a href="<?php echo NEWS_PATH_FICHE; ?>?newsId=<?php echo $newsId; ?>">
				<img class="newsListePhoto" src="<?php echo NEWS_ROOT.NEWS_REP_PHOTOS.$newsPhoto; ?>" style="width:<?php echo NEWS_LARGEUR_PICTO; ?>px;" alt="" title="<?php echo $newsTitre; ?>" />
				</a>
<?php		} ?>

<?php 			// Résumé du Contenu
				if(NEWS_RESUME_TYPE=='brut'){
					echo texte_resume_brut($newsContenu, NEWS_RESUME_NBRECAR); 
				} elseif(NEWS_RESUME_TYPE=='html'){
					echo texte_resume_html($newsContenu, NEWS_RESUME_NBRECAR); 
				} else {
					echo $newsContenu; 
				}
?>
				<a class="newsSuite" href="<?php echo NEWS_PATH_FICHE; ?>?newsId=<?php echo $newsId; ?>"><span>lire la suite</span></a>

<?php		if($newsFile != '') { ?>
				<a class="newsListeFile" href="<?php echo NEWS_ROOT.NEWS_REP_FILES.$newsFile; ?>" onclick="javascript:window.open(this.href); return false;">
				<span>Voir le Fichier joint</span></a>
<?php		} ?>
			</div>
		</div>
<?php
	} else {
		echo 'Mauvais identifiant de News';
	}
};
// ---------------------------------------------------

6-A3. Fonction : news_affiche_liste_colonne()

 
Sélectionnez
<?php
// ---------------------------------------------------
// 2/ FONCTION : LISTING des NEWS (avec résumé du contenu)
// ---------------------------------------------------
function news_affiche_liste_colonne($numPage)
{
	if(is_numeric($numPage) && $numPage>0)
	{
		// -------------------------
		global $pdo;
		// -------------------------
		// requete : toutes les News (CONFIG : Nombre Maxi à afficher -> NEWS_NBRE_MAXITOTAL)
		$news_total_query 		= "SELECT * FROM ".T_NEWS_TABLE." ".
								" WHERE news_publier = 1 ".		// uniquement les news publiées
								" ORDER BY news_date DESC ".
								" LIMIT 0, :newsNbreMaxiTotal ".
								";";
	  try {
		$pdo_select 			= $pdo->prepare($news_total_query);
		$pdo_select->bindValue(':newsNbreMaxiTotal', 	NEWS_NBRE_MAXITOTAL,		PDO::PARAM_INT);
		$pdo_select->execute();
		$news_total_nombre 		= $pdo_select->rowCount();
	  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
		// -------------------------
		// PAGINATION
		// On calcule le nombre de pages
		$nbreTotalPages 		= ceil($news_total_nombre / NEWS_NBRE_PARPAGE);
		// On calcule le numero du premier message qu'on prend pour le LIMIT de MySQL
		$numDebut 				= ($numPage - 1) * NEWS_NBRE_PARPAGE;
		// -------------------------
		// News à afficher sur la page
		$news_query 			= "SELECT * FROM ".T_NEWS_TABLE." ".
								" WHERE news_publier = 1 ".		// uniquement les news publiées
								" ORDER BY news_date DESC ".
								" LIMIT :numDebut,:newsNbreParPage ".
								";";
	  try {
		$pdo_select 			= $pdo->prepare($news_query);
		$pdo_select->bindValue(':numDebut', 		$numDebut,			PDO::PARAM_INT);
		$pdo_select->bindValue(':newsNbreParPage', 	NEWS_NBRE_PARPAGE,	PDO::PARAM_INT);
		$pdo_select->execute();
		$news_nombre 			= $pdo_select->rowCount();
		$news_rowAll			= $pdo_select->fetchAll();
	  } catch (PDOException $e) { echo 'Erreur SQL : '. $e->getMessage().'<br/>'; die(); }
		// -------------------------
		// Affichage de la PAGINATION
		news_pagination_pages($numPage, $nbreTotalPages); 
?>
		<div id="containerListing">
<?php	// -------------------------
		// Affichage des News
		if($news_nombre>0) {
			foreach ($news_rowAll as $news_row)
			{
				// -------------------------
				$newsId 			= intval($news_row['news_id']);
				// On recupere les infos dans la BD
				require(__DIR__ . '/news_data_fromBD.php');
				// -------------------------
				// Affichage de la news
				news_affiche_fiche_resume_colonne($newsId);
			}
		}
?>
		</div>
<?php
		// -------------------------
		// Affichage de la PAGINATION
		news_pagination_pages($numPage, $nbreTotalPages);
	}
};
// ---------------------------------------------------------------

6-A4. Fonction : news_affiche_fiche_resume_colonne()

 
Sélectionnez
<?php
// ---------------------------------------------------
// 1b/ FONCTION : FICHE de la News (LISTE sur plusieurs colonnes)
// Avec picto, résumé du contenu et lien vers la fiche de l'Article
// ---------------------------------------------------
function news_affiche_fiche_resume_colonne($newsId)
{
	if(is_numeric($newsId) && $newsId>0)
	{
		// -------------------------
		global $pdo;
		// -------------------------
		// On recupere les infos dans la BD
		require(__DIR__ . '/news_data_fromBD.php');
		// -------------------------
		// Nombre de colonnes : 1 à 6 (voir le style CSS : .newsListeColonne)
		$NbreCol	= ( NEWS_NBRE_COLONNE>0 && NEWS_NBRE_COLONNE<7 )? NEWS_NBRE_COLONNE : '';
?>
		<div class="newsListe newsListeColonne<?php echo $NbreCol; ?>">
			<div class="newsListeEntete">
				<h4 class="newsListeTitre"><?php echo $newsTitre; ?></h4>
				<span class="newsListeDate"> le <?php echo date('d/m/Y à H\hi', $newsDate); ?></span>
			</div>

			<div class="newsListeContenu">
<?php		if ($newsPhoto != '') { ?>
				<a href="<?php echo NEWS_PATH_FICHE; ?>?newsId=<?php echo $newsId; ?>">
				<img class="newsListePhoto" src="<?php echo NEWS_ROOT.NEWS_REP_PHOTOS.$newsPhoto; ?>" style="width:<?php echo NEWS_LARGEUR_PICTO; ?>px;" alt="" title="<?php echo $newsTitre; ?>" />
				</a>
<?php		} ?>

<?php 			// Résumé du Contenu
				if(NEWS_RESUME_TYPE=='brut'){
					echo texte_resume_brut($newsContenu, NEWS_RESUME_NBRECAR); 
				} elseif(NEWS_RESUME_TYPE=='html'){
					echo texte_resume_html($newsContenu, NEWS_RESUME_NBRECAR); 
				} else {
					echo $newsContenu; 
				}
?>
				<a class="newsSuite" href="<?php echo NEWS_PATH_FICHE; ?>?newsId=<?php echo $newsId; ?>"><span>lire la suite</span></a>

<?php		if($newsFile != '') { ?>
				<a class="newsListeFile" href="<?php echo NEWS_ROOT.NEWS_REP_FILES.$newsFile; ?>" onclick="javascript:window.open(this.href); return false;">
				<span>Voir le Fichier joint</span></a>
<?php		} ?>
			</div>
		</div>
<?php
	} else {
		echo 'Mauvais identifiant de News';
	}
};

// ---------------------------------------------------

6-A5. Fonction : news_pagination_pages()

 
Sélectionnez
<?php
// --------------------------------------------------------------
// FONCTION : PAGINATION (listing des News)
// --------------------------------------------------------------
function news_pagination_pages($numPage, $nbreTotalPages)
{
	// -------------
	$numLimit		= 5; 	// Limite : nombre de pages avant/après la page courante
	$sep			= '';	// Séparateur '', '-', '|', '/' : entre les numéros de pages
	// -------------
	$args 			= preg_replace('#(pg=[0-9]+&?)#', '', $_SERVER['QUERY_STRING']);
	$args 			= (!empty($args))?	'&'.$args : '';
	// -------------
	// PAGINATION
	if($nbreTotalPages > 1) 
	{
?>
		<div class="newsPagination">
<?php	echo $sep;
	  for ($i=1; $i<=$nbreTotalPages; $i++)
	  {
		// 1ère page
		if($i==1 && $numPage>($numLimit+1)) 
		{
			echo ' <a href="?pg='.$i.$args.'" title="Page '.$i.'">'.$i.'</a> '.$sep.'...'.$sep;
		}
		// page courante + $numLimit pages avant et après
		if(($numPage-1-$numLimit)<$i && $i<($numPage+1+$numLimit))
		{
		  if($i==$numPage) { // page courante
			echo ' <b>Page '.$i.'</b> '.$sep;
		  } else {
			echo ' <a href="?pg='.$i.$args.'" title="Page '.$i.'">'.$i.'</a> '.$sep;
		  }
		}
		// dernière page
		if($i==$nbreTotalPages && $numPage<($nbreTotalPages-$numLimit)) 
		{ 
			echo '...'.$sep.' <a href="?pg='.$i.$args.'" title="Page '.$i.'">'.$i.'</a>';
		}
	  }
?>
		</div>
<?php	} 	// (fin if nbreTotalPages)
};
// --------------------------------------------------------------

6-B. Fonctions de redimensionnement d'images

fonctions/fct_traitement_image.php :

Voir : PHP - Fonctions de redimensionnement d'images

Redimensionnement "à l'affichage" :
ou comment afficher ses images à la taille d'affichage voulue ?
L'image elle-même n'est pas modifiée, seules ses dimensions d'affichage sont recalculées.
- fonction fctaffichimage() : redimensionner des images "à l'affichage"

Redimensionnement "physique" :
modification du "poids" de l'image (nouvelle image aux dimensions spécifiées),
- fonction fctredimimage() : L'image finale est redimensionnée "en proportions".
- fonction fctdeformimage() : L'image finale est redimensionnée "sans proportions" (déformée).
- fonction fctcropimage() : L'image finale est "coupée" ("crop centré").

"Signature" d'image (petit "plus" !)
- fonction fcttexteimage() : "Signature" de l'image (ajout d'un texte à l'image : copyright, date, ou légende de l'image).

6-C. Fonctions de troncature de texte

fonctions/fct_resume_texte.php :

Voir : PHP - Fonctions de troncature de texte : Résumé "brut" ou Résumé "html"

"Résumé brut" d'un texte (html ou non) :
-> Le résumé est affiché sans formatage (sans balises html) ;
-> les balises html sont supprimées ;
-> le texte est tronqué à une nombre de caractères donné, en évitant de couper un mot.

"Résumé html" d'un texte (html) : -> Le résumé est affiché formaté, en conservant la mise en forme HTML du contenu ;
-> les balises html sont conservées (ce qui permet aussi d'afficher les smileys !) ;
-> le texte est tronqué à une nombre de caractères donné, en évitant de couper un mot.

7. Conclusion, remerciements

7-A. Conclusion

Ce système de Nouvelles avec photo et fichier joint devrait vous apporter satisfaction...
N'hésitez pas à télécharger l'archive et à tester la démonstration.

Cette source est parfaitement fonctionnelle en l'état.
L'intégration dans votre site ne devrait pas poser de problème majeur.

Ces fichiers sont open source, vous pouvez donc les modifier à votre convenance.

Contribution :
Toutes remarques, corrections, ajouts, permettant d'améliorer ou d'étoffer ce tutoriel seront les bienvenus.

Vous pouvez déposer vos commentaires ou poser vos questions sur cette source : 406 commentaires Donner une note à l'article (4.5)

Erreurs courantes :
- Bibliothèque GD : vérifiez qu'elle est bien activée (traitement des photos).
- Chez free.fr :
Pour la version 4 (mysql) : il faut créer un dossier sessions à la racine du site pour que ça fonctionne.
Pour la version 5 (PDO) : INUTILE d'essayer ! PAS de PDO !!

7-B. Remerciements

Un grand remerciement à tous les participants (Fonction de "résumé HTML", Création juin 2009 en collectif) : Xunil, jreaux62, s.n.a.f.u., christele_r, Doksuri, Patouche,
suite à une discussion fort intéressante concernant la "réparation de code HTML".

Remerciements à Claude Leloup pour sa relecture.

7-C. Tutoriels en rapport avec le sujet

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2009 Jérôme Réaux. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.