Pages

Showing posts with label php. Show all posts
Showing posts with label php. Show all posts

Wednesday, January 22, 2025

REMINDER : PHP memory setting and upload

 

Just a reminder for php settings I use.

If it helps anyone...


memory_limit = 512M


  • PHP’s memory_limit is per-script, just as a highway’s speed limit is per-vehicle.
  • It does not have a direct impact on the website's loading performance by itself and simply increasing it would not speed up your website.

If the value is too low for memory_limit, you will have this error :

PHP Fatal error: Allowed memory size of XXX bytes exhausted (tried to allocate XXX bytes)


post_max_size = 15M

upload_max_filesize = 10M


  • upload_max_filesize is the limit of any single file. 
  • post_max_size is the limit of the entire body of the request, which could include multiple files.


max_execution_time = 30

Saturday, August 14, 2021

PHP function to convert a CSV to JSON


I have the following CSV :

siret;nom long;nom_court;type;rue;code_postal;ville;pays
123;Nom long;Nom_court;Entreprise;rue du lac;21789;Marseille;France

And I need to obtain this one:

{
    "1": {
        "siret": "123",
        "nom long": "Nom long",
        "nom_court": "Nom_court",
        "type": "Entreprise",
        "address": {
            "ville": "Marseille",
            "code_postal": "21789",
            "country": "France"
        },
        ...
    },

I made this operation often and to simply my job I defined a generic function.

Initialization


First, we need to define elements like the separator by defining a constant : const SEPARATOR = ';';

We also need to identify columns associate to the JSON file. For example, in our CSV file, siret is at the first position. So we set : $columns[0]="siret";
Then longname is at the second position, so we set  $columns[1]="longname"; and so on.

Thus, at the beginning of our php file, we defined an array and set the correspondance between CSV and JSON :

$ini_array=array();
const SEPARATOR = ';';
// CSV files columns
$columns = array();
$columns[0]="siret";
$columns[1]="longname";
$columns[2]="shortname";
$columns[3]="type";
$columns[4]="rue";
$columns[5]="zipcode";
$columns[6]="city";
$columns[7]="country";


The next step is to identify dependency between elements. By using a simple array we set for example the address dependency :

$jsonHierarchy = array(
    "ville" => "address",
    "code_postal" => "address",
    "country" => "address",
);

In this array, we give all sub element of address in order to obtain this JSON structure :

        "address": {
            "ville": "Marseille",
            "code_postal": "21789",
            "country": "France"

These variables will be used by the convert method.

Read the CSV file


In my case, I used a config file where I stored the path of the CSV file path : PI_import_pathfile="C:\\tmp\file.csv"

I also have severeal environnement so I need to choose between them (Linux or Windows ) :

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    $ini_array = parse_ini_file("C:\\tmp\\config.ini");
} else {
    $ini_array = parse_ini_file("/root/config/config.ini");
}
$file=$ini_array["PI_import_pathfile"];

Call the method  convert_CSV_to_JSON()


The next step is to read the CSV file and convert it in JSON file :

if( file_exists($file)) {
    $csv = file_get_contents($file);

    $json = convert_CSV_to_JSON($csv, $columns, $jsonHierarchy);
    echo json_encode($json, JSON_PRETTY_PRINT);

} else {
    echo "File doesn't exist";
}

Method convert_CSV_to_JSON()

This is the code of the convert CSV to JSON method :

/**
 * Convert CSV content in an JSON array
 * Need to be improve for global use
 * @param String $csv_data Content of csv file
 * @param array $columns Field array of you Excel column
 *     e.g     // Excel column
 *              $columns[0]="uid";
 *              $columns[1]="code";
 * @param array $jsonHierarchy Field hierarchy
 * @return array for json encode
 */
function convert_CSV_to_JSON($csv_data, $columns, $jsonHierarchy){

    $json = array();
    $Data = str_getcsv($csv_data, "\n"); //parse the rows
    foreach($Data as $row_index => $Row) {
        $data = str_getcsv($Row, SEPARATOR);

        // skip the first row, since it's the headers
        if($row_index === 0) {
            continue;
        }
        $addr=array();
        foreach ($data as $column_index => $column_value) {


            // get the key for each entry
            if (isset($columns[$column_index])) {


                $label = $columns[$column_index];
                if (array_key_exists($label, $jsonHierarchy)) {

                    $parent = $jsonHierarchy[$label];
                    $addr[$label]=trim($column_value);
                    $json[$row_index][$parent]=$addr;
                } else {
                    $json[$row_index][$label] = trim($column_value);
                }
            }


        }
    }

    return $json;
}

Full code to convert CSV to JSON

<?php
/**
 * Read a csv file and produce an JSON output in order to import organisations.
 *
 * Note :
 * - The column order is important and set in the convert_CSV_to_JSON§.
 * - csv in UTF8 format.
 *
 * e.g :
 * php convertCSVtoJSON.php > organisationPI.json
 * php public/index.php oscar organizationsjson:sync /root/PI/organisationPI.json
 *
 */
$ini_array=array();
const SEPARATOR = ';';
// Excel columns
$columns = array();
$columns[0]="siret";
$columns[1]="longname";
$columns[2]="shortname";
$columns[3]="type";
$columns[4]="rue";
$columns[5]="zipcode";
$columns[6]="city";
$columns[7]="country";

/*$columns[0]="uid";
$columns[1]="code";
$columns[2]="shortname";
$columns[3]="longname";
$columns[4]="type";
$columns[5]="address";
$columns[6]="city";
$columns[7]="zipcode";
$columns[8]="country";
$columns[9]="phone";
$columns[10]="url";
$columns[11]="email";
$columns[12]="siret";
$jsonHierarchy = array(
    "address1" => "address",
    "city" => "address",
    "zipcode" => "address",
    "country" => "address",
);
//PI_import_pathfile="C:\\tmp\\tmp.csv"
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    $ini_array = parse_ini_file("C:\\tmp\\config.ini");
} else {
    $ini_array = parse_ini_file("/tmp/config.ini");
}
$file=$ini_array["PI_import_pathfile"];
if( file_exists($file)) {
    $csv = file_get_contents($file);
    $json = convert_CSV_to_JSON($csv, $columns, $jsonHierarchy);
    echo json_encode($json, JSON_PRETTY_PRINT);
} else {
    echo "Le fichier d'import CSV n'existe pas !";
}


/**
 * Convert CSV content in an JSON array
 * Need to be improve for global use
 * @param String $csv_data Content of csv file
 * @param array $columns Field array of you Excel column
 *     e.g     // Excel column
 *              $columns[0]="uid";
 *              $columns[1]="code";
 * @param array $jsonHierarchy Field hierarchy
 * @return array for json encode
 */
function convert_CSV_to_JSON($csv_data, $columns, $jsonHierarchy){

    $json = array();
    $Data = str_getcsv($csv_data, "\n"); //parse the rows
    foreach($Data as $row_index => $Row) {
        $data = str_getcsv($Row, SEPARATOR);

        // skip the first row, since it's the headers
        if($row_index === 0) {
            continue;
        }
        $addr=array();
        foreach ($data as $column_index => $column_value) {
            // get the key for each entry
            if (isset($columns[$column_index])) {
                $label = $columns[$column_index];
                if (array_key_exists($label, $jsonHierarchy)) {


                    $parent = $jsonHierarchy[$label];
                    $addr[$label]=trim($column_value);
                    $json[$row_index][$parent]=$addr;
                } else {
                    $json[$row_index][$label] = trim($column_value);
                }
                //exit(1);
                /*switch ($column_index) {
                    case 5:
                        $addr["address1"]=trim($column_value);
                        $json[$row_index]["address"]=$addr;
                        break;
                    case 6:
                        $addr["city"]=trim($column_value);
                        $json[$row_index]["address"]=$addr;
                        break;
                    case 7:
                        $addr["zipcode"]=trim($column_value);
                        $json[$row_index]["address"]=$addr;
                        break;
                    case 8:
                        $addr["country"]=trim($column_value);
                        $json[$row_index]["address"]=$addr;
                        break;
                    default:
                        $json[$row_index][$label] = trim($column_value);
                }*/
            }
        }
    }
    return $json;
}


Version : PHP 7.3.1



Sunday, July 25, 2021

Auto-generated menu : a simple idea to save time in your developpement


Most of the time, I need to do small developpement in my job and I need to do it quickly. I have to think how to improve my developpement.For example, recently, I need to add menu items quickly and when you read the code of your web site you've made few month later, it 's sometimes quite difficult. 
That's why I decided to save my menu in database. Now, menu is auto-generated.

Why do I need to save a menu in database ? 

In my work, I made a business web site with cake-php 3.9.X , Postgresql database and Bootstrap.

The goal of this tool is to display reports (generated automatically in pdf with Businness Object).Every report has a specific name.If click on an item of my menu, I need severeal paremeters in order to display the correct report like name, date, enable or disable... 

Here is an example of a  menu :

I've met a problem when I wanted  to add a submenu, I need to write to much codes :

<?php

//
$ssdomain='INFORMATION';
if($selectedSSDomain == $ssdomain) {
$ssdomainLabel = "<span class='navbar-custom'>CONTACT</span>";
} else {
$ssdomainLabel = "CONTACT";
}
echo "<form method='post' action='index.php' id='form_contact'>";
echo "<input type='hidden' name='domain' value='Information'/>";
echo "<input type='hidden' name='ssdomain' value='CONTACT'/>";
echo "<input type='hidden' name='startWithReport' value='key_1'/>";
if (isset($_POST['chooseReportDate'])) {
$tmpDate = $_POST['chooseReportDate'];
echo "<input type='hidden' name='chooseReportDate' value=\"$tmpDate\"/>";
}
if(isset($_POST['select_org']) ) {
$code = $_POST['select_org'];
echo "<input type='hidden' name='select_org' value=\"$code\"/>";
}

echo "<a class='dropdown-item' onclick=\"document.getElementById('form_contact').submit(); return false;\" >$ssdomainLabel</a>";

echo "</form>";

In my business, it happens quite often (every 6 month) and I need to remember all parameters !That's why I decided to save my menu in database. Now, it's really easy to add a new menu !


Table Menu

First, we need to add all your menu information in a table of our database as text, position, enable...

Here is the Menu table :





drop table yuzu.menu;
CREATE TABLE yuzu.menu (
                      id int primary key ,
                      id_parent int,
                      shortkey varchar(50) NOT NULL,
                      name varchar(50) NOT NULL,
                      position int,
                      grey bool
);


This table contains :
  • id : menu id
  • id_parent : To indicate that the menu is a submenu
  • shortkey : Use to identify the choosen menu
  • position : We need to order menu.
For each level of menu, we indicated the position. For example, HOME is first (position 1) then INFORMATION is second.
The submenu is also sortered with CONTACT in second position and PROFILE in the first position :



HomeController

In my controller, I retreived the Menu table and stored it in a session.    


Display auto generated menu

I wrote some code to display the menu automatically. To achieved that, I defined one method : function displayMenu($menus){}



Here is the code of two methods :

        <?php


        function getSortedMenu($menus, $currentIdParent) {
            $mainMenus = array();
            // Sort Menu
            foreach ($menus as $arr) {
                $submenus = $arr[0];
                $idParent = $submenus['id_parent'];
                if ($idParent == $currentIdParent) {
                    $position = $submenus['position'];
                    $mainMenus[$position]=$submenus;
                }
            }
            ksort($mainMenus);
            return $mainMenus;
        }


        function displayMenu($menus) {
            $mainMenus = getSortedMenu($menus, 0);
            foreach($mainMenus as $levelOnes) {

                echo "<li class=\"nav-item dropdown\">";
                $shortkey = "dropdown_".$levelOnes['shortkey'];
                echo "<a class=\"nav-link dropdown-toggle text-menu\" id='$shortkey' data-toggle=\"dropdown\" href='#'>".$levelOnes['name']."</a>";
                echo "<div class='dropdown-menu' aria-labelledby='$shortkey'>";

                foreach ($menus as $arr) {

                    $menu = $arr[0];
                    if($menu['id_parent']==$levelOnes['id']) {
                        $shortkey = "form_".$menu['shortkey'];

                        echo "<form method='post' action='/home' id='".$shortkey."'>";
                        $disabled="";
                        if ($menu['grey']) {
                            $disabled='disabled';
                        }
                        echo "<input type='hidden' name='menu_selected_id' value='".$menu['id']."'/>";
                        echo "<a class='dropdown-item $disabled text-menu' href='#'>" . $menu['name'] . "</a>";
                        echo "</form>";
                    }
                }
                echo "</div>";
                echo "</li>";
            }
        }
        ?>

This code used bootstrap and will certainly be improved.I think it's often a good way to auto-generated things. I hope it will give you some idea for your source code. 

Notes :

  • We have only two levels because I didn't need a level three of my menu.
  • The next step  is to manage authorization ! 

Versions :

CakePHP 3.9
Postgresql 9.6
Bootstrap 4.2.1

Saturday, June 26, 2021

Code inspection warning : Optional parameter is provided before required

I am used to inspect my source code and tried to solve warning. I've had the warning : Optional parameter is provided before required

This warning occured on this line  : 

function generateMenu($level=1, $label, $code, $labos) {

}

The explanation of this warning is quite simple.Optional parameters (with default values) always should be at the end, otherwise they are not optional !

So you have to write your function like this : 

function generateMenu($label, $code, $labos, $level=1) {

}

PHP Storm 2021.1.3
PHP 7.1

Wednesday, June 16, 2021

cake-php : create and use a configuration file

 

This is a reminder to use variables from a configuration file with cake-php 3.8 framework.

Configuration file

First, create yuzu_config.php in config directory :

Then add your configuration like the following :

vi yuzu_config.php
<?php
return [
'organisation' => [
    'LABO' => [
        'code' => '3',
        'label' => 'label1',
        'level' => '1'
        ]
]];

In bootstrap.php, you have to load your configuration file :

Configure::load('yuzu_config', 'default');



The last step is to use it :

use Cake\Log\Log;
use Cake\Core\Configure;

$arr = Configure::read('organisation.LABO');
$code = $arr['code'];
Log::debug($code);


Version : cake-php 3.8.x





Friday, June 4, 2021

How to add CAS authentication to a PHP website ?

The main purpose of this article is to explain what you have to do in order to activate the CAS authentication. 

We will cover all steps needed to begin quickly with CAS !

My configuration :

  • Debian 9 Stretch
  • PHP 7.0
  • jasig/phpcas 1.4

Installation

You need the following Debian package :

apt-get install wget php-cli php-zip unzip

apt-get install php7.0-curl

Then, you have to install composer :

cd /root

wget -O composer-setup.php https://getcomposer.org/installer

php composer-setup.php --install-dir=/usr/local/bin --filename=composer

The next step is to add  the file composer.json with the referencies of phpcas:

{

    "require": {

        "jasig/phpcas": "^1.4"

    }

}

The composer update command retreives the phpcas library in your project (in vendor directory).So you need to execute the following :

cd /var/www/html/myproject

composer update

If you use git, don't fortget to add these lines in your .gitignore file :

vendor

composer.lock


How to use it in your PHP file ?

Here is a sample :

require __DIR__ . '/vendor/autoload.php';


// Enable debugging
phpCAS::setLogger();
// Enable verbose error messages. Disable in production!
phpCAS::setVerbose(true);
//phpCAS::setDebug("./err.log");

// initialize phpCAS
phpCAS::client(CAS_VERSION_2_0,'monserveur_cas.toto.fr',443,'/cas',FALSE);

// force CAS authentication
//phpCAS::setCasServerCACert($cas_server_ca_cert_path);
phpCAS::setNoCasServerValidation();
phpCAS::forceAuthentication();

// at this step, the user has been authenticated by the CAS server
// and the user's login name can be read with phpCAS::getUser().

if (!phpCAS::checkAuthentication()) {
die("Echec !");
}
$login = phpCAS::getUser();
print_r(phpCAS::getAttributes());
echo "===> LOGIN : $login";

PlayConsole : suppression des warnings lors de la publication (minify, symbole de debogage...)

Lors de la publication des versions dans la PlayConsole, j'avais 2 warnings pour indiquer qu'il était possible de réduire et d'o...