Today a perform a migration of a Joomla 3.8 site from a server to another. All works well except only one custom module. The module works correctly before the migration but after the migration the error received is this one:
2022/05/04 17:15:23 [error] 2572#0: *1 FastCGI sent in stderr: "PHP message: PHP Fatal error: Cannot declare class PdfToJpg, because the name is already in use in /www/wwwroot/readeat.it/Joomla/modules/mod_readeat_menu_upload/mod_readeat_menu_upload.php on line 7" while reading response header from upstream, client: 84.33.118.182, server: readeat.it, request: "POST /index.php/it/il-mio-locale/carica-menu HTTP/2.0", upstream: "fastcgi://unix:/tmp/php-cgi-74.sock:", host: "test.readeat.it", referrer: "https://test.readeat.it/index.php/it/il-mio-locale/carica-menu"
The old server was a built-in server with Plesk Obsidian and Apache server, now i migrate all to a NGinx based server. The version of PHP is 7.4 in both scenarios.
Here the Nginx configuration of the new server:
user www www;
worker_processes auto;
error_log /www/wwwlogs/nginx_error.log crit;
pid /www/server/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;
stream {
log_format tcp_format '$time_local|$remote_addr|$protocol|$status|$bytes_sent|$bytes_received|$session_time|$upstream_addr|$upstream_bytes_sent|$upstream_bytes_received|$upstream_connect_time';
access_log /www/wwwlogs/tcp-access.log tcp_format;
error_log /www/wwwlogs/tcp-error.log;
include /www/server/panel/vhost/nginx/tcp/*.conf;
}
events
{
use epoll;
worker_connections 51200;
multi_accept on;
}
http
{
#AAPANEL_FASTCGI_CONF_BEGIN
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_path /dev/shm/nginx-cache/wp levels=1:2 keys_zone=WORDPRESS:100m inactive=60m max_size=1g;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
#AAPANEL_FASTCGI_CONF_END
include mime.types;
#include luawaf.conf;
include proxy.conf;
default_type application/octet-stream;
server_names_hash_bucket_size 512;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;
sendfile on;
tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6].";
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server_tokens off;
access_log off;
server
{
listen 888;
server_name phpmyadmin;
index index.html index.htm index.php;
root /www/server/phpmyadmin;
location ~ /tmp/ {
return 403;
}
#error_page 404 /404.html;
include enable-php.conf;
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*.(js|css)?$
{
expires 12h;
}
location ~ /.
{
deny all;
}
access_log /www/wwwlogs/access.log;
}
include /www/server/panel/vhost/nginx/*.conf;
}
And the code of the module:
<?php
/********************************************************************************************************************************************************* */
define("SKIP_API_CALL", "false");
class PdfToJpg {
//Oggetto API
private $ApiResource;
private $numOfPages;
private $saveFilePath;
//Autenticazione
private $projectPublic = "";
private $projectSecret = "";
private $baseFileName = "file_0";
function __construct($projectPublic, $projectSecret) {
$this->projectPublic = $projectPublic;
$this->projectSecret = $projectSecret;
//Recupero della libreria ILovePdf
require_once(JPATH_LIBRARIES. '/ilovepdf/init.php');
//Creazione dell'oggetto per interrogazione API
$this->ApiResource = new IlovepdfIlovepdf($this->projectPublic, $this->projectSecret);
}
public function convertPdf($pdfFilePath, $pdfFileName) {
if(SKIP_API_CALL != "true") {
$restTask = $this->ApiResource->newTask('pdfjpg');
$restTask->setOutputFilename($this->baseFileName);
$restTask->addFile($pdfFilePath . $pdfFileName);
$restTask->execute();
$restTask->download($pdfFilePath);
}
}
public function extractAndSave($filepath, $fileName, $newName = "menu") {
//Elimino l'estensione del file
$newName = strstr($newName, '_', true);
if (file_exists($filepath . $fileName)) {
$zip = new ZipArchive();
$result = $zip->open($filepath . $fileName);
if($result === true) {
$this->numOfPages = $zip->numFiles;
$result = $zip->extractTo($filepath);
$zip->close();
for($i=1; $i <= $this->numOfPages; $i++) {
$tmpOldName = $filepath . $this->baseFileName . "-" . str_pad($i, 4, '0', STR_PAD_LEFT) . ".jpg";
$tmpNewName = $filepath . $newName . "_" . $i . ".jpg";
rename($tmpOldName, $tmpNewName);
}
return true;
}
else {
return false;
}
}
else {
if(file_exists($filepath . $this->baseFileName . "-0001.jpg")) {
$tmpOldName = $filepath . $this->baseFileName . "-0001.jpg";
$tmpNewName = $filepath . $newName . "_1.jpg";
rename($tmpOldName, $tmpNewName);
return true;
}
else
return false;
}
}
public function getNumOfPages() {
return $this->numOfPages;
}
}
/********************************************************************************************************************************************************* */
class ReadEatPlaceProfile {
private $placeIdOffset = 1000;
public $name;
public $timeWindow;
public $id;
public $ownerId;
private $isNewUser = false;
private static $joomlaDb;
private static $isInitizlized = false;
function __construct($userObj, $customFields, $joomlaDbObj) {
$this->setDBObject($joomlaDbObj);
//Rimozione di tutti gli special Chars dalla stringa nome locale
$this->name = preg_replace('/[^A-Za-z0-9-]/', '', $userObj->name);
$this->timeWindow = $customFields[0]->value;
$this->ownerId = $userObj->id;
$tmpPlaceId = $this->getPlaceIdFromUserId();
if($tmpPlaceId == NULL || !$tmpPlaceId) {
$this->isNewUser = true;
$this->id = $this->getNewPlaceId($userObj->id);
}
else {
$this->id = $tmpPlaceId;
}
}
//Funzione epr l'inizializzazione degli oggetti contenenti le risorse Joomla
public function initialize($joomlaDbObj) {
if(!self::$isInitizlized) {
setDBObject($joomlaDbObj);
}
}
//Query per il check della entry del locale all'interno delle tabelle readeat
public function getPlaceIdFromUserId() {
$query = self::$joomlaDb->getQuery(true);
$query->select('placeId')
->from(self::$joomlaDb->quoteName('rdet_locali'))
->where('userId = ' . $this->ownerId);
self::$joomlaDb->setQuery($query);
$queryedPlaceId = self::$joomlaDb->loadResult();
return $queryedPlaceId;
}
public function insertPlaceIdForUserid() {
$query = self::$joomlaDb->getQuery(true);
$query->insert(self::$joomlaDb->quoteName('rdet_locali'))
->columns(array('userId', 'placeId', 'placeName', 'timeWindow'))
->values("$this->ownerId, $this->id, '$this->name', '$this->timeWindow'");
self::$joomlaDb->setQuery($query);
self::$joomlaDb->execute();
}
public function insertNewMenuRecord($fileName, $fileType, $numOfPages, $data) {
$name = preg_replace('/[/[^a-zA-Z0-9 ]/', '', $data['name']);
$type = $data['type'];
$lang = $data['lang'];
$isPredefined = 0;
if(!$this->menuExists($lang))
$isPredefined = 1;
self::$joomlaDb->transactionStart();
$query = self::$joomlaDb->getQuery(true);
$query->insert(self::$joomlaDb->quoteName('rdet_menu'))
->columns(array('placeId', 'isPredefined', 'language', 'type', 'name'))
->values("$this->id, $isPredefined, '$lang', '$type', '$name'");
self::$joomlaDb->setQuery($query);
self::$joomlaDb->execute();
$query = self::$joomlaDb->getQuery(true);
$query->insert(self::$joomlaDb->quoteName('rdet_files_menu'))
->columns(array('menuId', 'fileName', 'fileType', 'numberOfPages'))
->values("LAST_INSERT_ID(), '$fileName', '$fileType', '$numOfPages'");
self::$joomlaDb->setQuery($query);
self::$joomlaDb->execute();
self::$joomlaDb->transactionCommit();
}
public function menuExists($language) {
$query = self::$joomlaDb->getQuery(true);
//Controllo che non sia giĆ attivo un menu caricato
$query->select(self::$joomlaDb->quoteName('menuId'))
->from(self::$joomlaDb->quoteName('rdet_menu'))
->where(self::$joomlaDb->quoteName('rdet_menu.placeId') . "=". self::$joomlaDb->quote($this->id) . " AND language = " . self::$joomlaDb->quote($language));
self::$joomlaDb->setQuery($query);
$menuIdExsists = self::$joomlaDb->loadResult();
if($menuIdExsists == NULL || !$menuIdExsists)
return false;
return true;
}
public function isNewUser() {
return $this->isNewUser;
}
private function setDBObject($joomlaDbObj) {
self::$joomlaDb = $joomlaDbObj;
}
private function getNewPlaceId($currentUserid) {
return (int)$currentUserid + $this->placeIdOffset;
}
public function getPlaceId() {
return $this->id;
}
}
/********************************************************************************************************************************************************* */
class ReadEatMenuUpload {
//Oggetto Locale
public $ReadEatPlaceProfile;
private $menuFilePath;
private $filesExtension;
private $filesNumber;
private $tmpFiles;
private $pdfConverter;
private $fileName;
//Impostazioni
private $MODULE_PARAM = array();
function __construct($MODULE_PARAM) {
$this->fileName = "";
$this->MODULE_PARAM = $MODULE_PARAM;
//Oggetto PDF Converter
$this->pdfConverter = new PdfToJpg($MODULE_PARAM['API_PUBLIC'], $MODULE_PARAM['API_SECRET']);
$currentUserId = JFactory::getUser()->id;
$this->ReadEatPlaceProfile = new ReadEatPlaceProfile(JFactory::getUser(), FieldsHelper::getFields('com_users.user', ['id'=> $currentUserId]), JFactory::getDBO());
}
public function checkAuthorization($currentUserGroups) {
foreach($this->MODULE_PARAM['ALLOWED_GROUPS'] as $allowedGroups)
foreach($currentUserGroups as $userGroup)
if($userGroup == $allowedGroups)
return true;
return false;
}
public function handlefiles($filesArray, $data) {
$this->tmpFiles = $filesArray;
$this->filesNumber = count($this->tmpFiles["name"]);
if($this->filesNumber > $this->MODULE_PARAM['MAX_FILE_TO_UPLOAD']) {
if($DEBUG_MODE == 1) {
$page .= "<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_MAX_FILE_ERR' ) . "</p>";
}
}
//Preparo nomi e percorso di salvataggio
$this->menuFilePath = $this->MODULE_PARAM['FILE_SAVE_PATH'] . strval($this->ReadEatPlaceProfile->getPlaceId()) . "/";
if($this->checkfileType()) {
if($this->saveFiles()) {
if($this->filesExtension == "pdf") {
$this->ReadEatPlaceProfile->insertNewMenuRecord($this->fileName, ".jpg", $this->pdfConverter->getNumOfPages(), $data);
}
else {
$this->ReadEatPlaceProfile->insertNewMenuRecord($this->fileName, "." . $this->filesExtension, $this->filesNumber, $data);
}
header("location: " . JUri::base() . "index.php" . "/" . $this->MODULE_PARAM['ON_SUCCESS_UPLOAD_ALIAS']);
}
}
else {
$message = "<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_UPLOAD_ERR' ) . "</p>";
JFactory::getApplication()->enqueueMessage($message, "error");
}
}
public function saveFiles() {
if($this->MODULE_PARAM['TIMESTAMP_FILE_NAME'] == 1) {
$date = new DateTime();
$this->fileName = $date->getTimestamp();
}
else {
$this->fileName = $this->MODULE_PARAM['BASE_FILE_NAME'];
}
for($i=0; $i < $this->filesNumber; $i++) {
//Aggiungo al nome del file l'indice specifico e l'estensione
$localFileName = $this->fileName . "_" . strval($i+1) . "." . $this->filesExtension;
if(!JFile::upload($this->tmpFiles['tmp_name'][$i], $this->menuFilePath . $localFileName)) {
//Qui fallisce la chiamata joomla all'upload
JFactory::getApplication()->enqueueMessage("<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_FILE_ERR' ) . "</p>", "error");
return false;
}
else {
if($this->filesExtension == "pdf") {
$this->pdfConverter->convertPdf($this->menuFilePath, $localFileName);
$result = $this->pdfConverter->extractAndSave($this->menuFilePath, "output.zip", $localFileName);
if($result) {
JFactory::getApplication()->enqueueMessage("<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_UPLOAD_OK' ) . "</p>");
return true;
}
else {
JFactory::getApplication()->enqueueMessage("<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_CONV_ERR' ) . "</p>");
return false;
}
}
}
}
JFactory::getApplication()->enqueueMessage("<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_UPLOAD_OK' ) . "</p>");
return true;
}
public function checkfileType() {
for($i = 0; $i < $this->filesNumber; $i++) {
//Variabili di stato per il controllo degli errori e gli step
$typeError = true;
$mimeTypeError = true;
//Controllo dell'estensione
$uploadedFileNameParts = explode('.', $this->tmpFiles['name'][$i]);
$uploadedFileExtension = strtolower(array_pop($uploadedFileNameParts));
//Controllo singolo file in caso di pdf
if($uploadedFileExtension == "pdf" && $this->filesNumber > 1) {
$message = "<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_MORE_PDF_ERR' ) . "</p>";
JFactory::getApplication()->enqueueMessage($message, "error");
return false;
}
//Controllo che le estensioni siano tutte uguali
if(!empty($filesExtension)) {
if($this->filesExtension != $uploadedFileExtension) {
//Basta una sola estensione diversa per far fallire l'upload
return false;
}
}
//Controllo che l'estensione corrisponda a quelle consentite
foreach($this->MODULE_PARAM['ALLOWED_EXTENSIONS'] as $key => $value) {
if($value == $uploadedFileExtension) {
//trovo una corrispondenza quindi esco
if(empty($filesExtension))
$this->filesExtension = $uploadedFileExtension;
$typeError = false;
break;
}
else {
$typeError = true;
}
}
//Controllo che i files siano effettivamente una immagine o un pdf per questioni di security
//Il meccanismo sfrutta i MIME Types
$fileInfo = mime_content_type($this->tmpFiles['tmp_name'][$i]);
foreach($this->MODULE_PARAM['ALLOWED_MIME_TYPES'] as $key => $value) {
if($value == $fileInfo) {
//Trovo una corrispondenza quindi esco
$mimeTypeError = false;
break;
}
else {
$mimeTypeError = true;
}
}
}
return !($mimeTypeError || $typeError);
}
public function isNewUser() {
return $this->ReadEatPlaceProfile->isNewUser();
}
public function insertPlaceIdForUserid() {
$this->ReadEatPlaceProfile->insertPlaceIdForUserid();
}
public function menuExists() {
return $this->ReadEatPlaceProfile->menuExists();
}
public function getUploadedPlaceId() {
return $this->ReadEatPlaceProfile->getPlaceId();
}
}
/********************************************************************************************************************************************************* */
use JoomlaCMSFactory;
$MODULE_PARAM = array();
//Parametri per gruppi consentiti
$MODULE_PARAM['ALLOWED_GROUPS'] = explode(",", $params->get('allowed_groups', "locali"));
//Parametri per redirect
$MODULE_PARAM['AUTH_ERROR_ALIAS'] = $params->get('auth_error_alias', "locali");
$MODULE_PARAM['ON_SUCCESS_UPLOAD_ALIAS'] = $params->get('success_upload_alias', "rdetqrviewer");
$MODULE_PARAM['EDIT_PROFILE_ALIAS'] = JUri::base() . "index.php" . "/" . $params->get('edit_profile_alias', "il-mio-profilo");
//Parametri per l'upload
$MODULE_PARAM['BASE_FILE_NAME'] = $params->get('base_file_name', "menu");
$MODULE_PARAM['TIMESTAMP_FILE_NAME'] = (int)$params->get('ts_file_name', 0);
$MODULE_PARAM['MAX_FILE_TO_UPLOAD'] = (int)$params->get('max_file_upload', 40);
$MODULE_PARAM['ALLOWED_EXTENSIONS'] = explode(',', $params->get('allowed_extensions', "jpeg,jpg,png,pdf"));
$MODULE_PARAM['ALLOWED_MIME_TYPES'] = explode(',', $params->get('allowed_mime_types', 'image/jpeg,image/pjpeg,image/png,image/x-png,application/pdf'));
$MODULE_PARAM['FILE_SAVE_PATH'] = JPATH_ROOT . "/" . $params->get('file_save_path', "readeat/menus/");
//Debug variables
$MODULE_PARAM['API_PUBLIC'] = $params->get('ilovepdf_api_public', "project_public_a5113e260b65faf6a453c6a976ba303d_T1Oon5dc7b86cd720576593cf39c8bd561f8e");
$MODULE_PARAM['API_SECRET'] =$params->get('ilovepdf_api_secret', "secret_key_cf0c0bc1a7699937817ccc19319c43cc_o-3zIb2e8cd02e98f4e673a8c9bec9ae153e0");
$MODULE_PARAM['DEBUG_MODE'] = (int)$params->get('debug_mode', 0);
$page = "";
$readEatMenuUpload = new ReadEatMenuUpload($MODULE_PARAM);
$currentUserGroups = JFactory::getUser()->groups;
if(!$readEatMenuUpload->checkAuthorization($currentUserGroups)) {
//L'utente non fa parte del gruppo autorizzati
header("location: " . JUri::base() . "index.php" . "/" . $AUTH_ERROR_ALIAS);
}
//Oggetti Joomla
$doc = JFactory::getDocument();
if($readEatMenuUpload->isNewUser())
$readEatMenuUpload->insertPlaceIdForUserid();
//Gestione dei file caricati
if(isset($_FILES['menuFile'])) {
if(empty($_POST['menuName'])) {
$message = "<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_NONAME_ERROR' ) . "</p>";
JFactory::getApplication()->enqueueMessage($message, "error");
}
else {
$data = array();
$data['name'] = $_POST['menuName'];
$data['type'] = $_POST['menuType'];
$data['lang'] = $_POST['menuLang'];
$readEatMenuUpload->handlefiles($_FILES['menuFile'], $data);
}
}
$message = "
<p class="rdetInfoMessage">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_MSG_HOWTO' ) . "</p>
";
$page .= "
<button onclick='showHelp()' class="helpButton">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_HELP_BUTTON' ) . "</button>
<div id='rdetUploadDiv'>
<form data-intro='" . JText::_( 'MOD_READEAT_MENU_UPLOAD_HELP_INTRO' ) . "' id='rdetUploadForm' method='POST' enctype="multipart/form-data"'>
<div data-intro='" . JText::_( 'MOD_READEAT_MENU_UPLOAD_HELP_NAME' ) . "' class="rdetFieldContainer">
<label class="rdetFormLabel" for="rdetMenuName">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_MENU_NAME' ) . "</label>
<input type="text" id='rdetMenuName' name="menuName">
</div>
<div data-intro='" . JText::_( 'MOD_READEAT_MENU_UPLOAD_HELP_TYPE' ) . "' class="rdetFieldContainer">
<label class="rdetFormLabel" for="rdetMenuType">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_MENU_TYPE' ) . "</label>
<select id='rdetMenuType' name="menuType">
<option value="cucina">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_TYPE_COOK' ) . "</option>
<option value="vini">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_TYPE_WINE' ) . "</option>
<option value="cocktail">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_TYPE_COCKTAIL' ) . "</option>
<option value="dolci">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_TYPE_DESSERT' ) . "</option>
<option value="allergeni">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_TYPE_ALLERGENS' ) . "</option>
<option value="altro">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_TYPE_OTHER' ) . "</option>
</select>
</div>
<div data-intro='" . JText::_( 'MOD_READEAT_MENU_UPLOAD_HELP_LANG' ) . "' class="rdetFieldContainer">
<label class="rdetFormLabel" for="rdetMenuLang">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_LANG' ) . "</label>
<select id='rdetMenuLang' name="menuLang">
<option value="it-IT">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_IT' ) . "</option>
<option value="en-GB">" . JText::_( 'MOD_READEAT_MENU_UPLOAD_LBL_EN' ) . "</option>
</select>
</div>
<div class="rdetFieldContainer">
<input data-intro='" . JText::_( 'MOD_READEAT_MENU_UPLOAD_HELP_FILE' ) . "' class="btn rdetUploadInput" type="file" name="menuFile[]" multiple>
<input class="button rdetUploadInput" type="submit" value="" . JText::_( "MOD_READEAT_MENU_UPLOAD_LBL_UPLOAD' ) . "'>
</div>
</form>
</div>
";
JFactory::getApplication()->enqueueMessage($message);
$doc->addStyleSheet(JURI::root(true) . "/modules/mod_readeat_menu_upload/libs/introjs/introjs.min.css");
$doc->addScript(JURI::root(true) . '/modules/mod_readeat_menu_upload/libs/introjs/intro.min.js');
$doc->addStyleSheet(JURI::root(true) . "/modules/mod_readeat_menu_upload/css/default.css");
$doc->addScript(JURI::root(true) . '/modules/mod_readeat_menu_upload/js/script.js');
require JModuleHelper::getLayoutPath('mod_readeat_menu_upload', $params->get('layout', 'default'));
?>
Do someone see this before?
thanks