[PHP] Classe in PHP per autenticazione utenti con LDAP

Immaginiamo di avere un server Windows con dominio chiamato torregatti.local. Possiamo effettuare l’autenticazione tramite PHP utilizzando il metodo LDAP (Lightweight Directory Access Protocol).

Anzitutto assicuriamoci di avere attiva la libreria LDAP all’interno del PHP.

Su Linux possiamo installare la libreria, per esempio con Ubuntu digitiamo:

Mentre su Windows, per esempio usando XAMPP, sarà sufficiente attivare l’estensione nel file php.ini, rimuovendo il commento alla seguente riga:

Che diventerà quindi:

Fatto questo possiamo creare una classe che si occupi del processo di login.

Prima di procedere vediamo il minimo indispensabile per effettuare il processo:

In questo caso stiamo entrando con l’utente amministratore TORREGATTI\ADMINISTRATOR che ha per password Password123

Ricordiamoci che nel nostro esempio il dominio è torregatti.local e il server si trova sull’indirizzo 192.168.56.1. Ci stiamo collegando con una connessione non sicura, usando il protocollo ldap anziché ldaps (richiederebbe la porta 636).

Possiamo creare una classe che effettui tutto il processo di login e ci permetta di verificare l’autenticazione mediante i cookie, nella maniera seguente:

Per effettuare il login sarà sufficiente configurare la classe nella maniera seguente:

Abbiamo aggiunto una nostra chiave casuale e segreta che verrà utilizzata per la costruzione del hash nei cookie.

Per verificare che l’utente sia autenticato, una volta terminato il processo di login, sarà sufficiente richiamare:

Per effettuare il logout sarà sufficiente richiamare:

E’ molto probabile che l’inserimento di username e password lo si voglia fare dopo aver costruito l’oggetto per l’autenticazione LDAP, in tal caso si potrebbe procedere nella maniera seguente:

Con il metodo getError() è possibile verificare gli altri eventuali errori durante il processo di autenticazione, sfruttando le costanti della classe.

Vedi articolo

[prestashop] Expression #11 of SELECT list is not in GROUP BY clause and contains nonaggregated column

Problema: dopo un cambio di database (senza alcuna modifica al dominio) in Prestashop non vengono più visualizzati i prodotti nelle singole categorie e accedendo al pannello di controllo si presenta un errore del tipo Expression #11 of SELECT list is not in GROUP BY clause and contains nonaggregated column [...] which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

Soluzione: Modificare l’opzione sql_mode in sql_mode='STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION'

Nel caso specifico sarebbe sufficiente modificare la variabile globale sql_mode eseguendo la query:

Purtroppo questa modifica, che sarebbe quella ottimale e definitiva, non è sempre possibile da attuare a causa dei permessi sul database. Nel caso in cui non la si possa mettere in pratica sarà sufficiente modificare il file classes/db/DbPDO.php nella maniera seguente.

Aprendo il file alla riga 63 si troverà la seguente funzione:

Modificare la funzione nella maniera seguente, aggiungendo prima di return il pezzo di codice evidenziato:

Questa soluzione è stata presa da questo commento nel forum ufficiale.

Vedi articolo

[magento2] Script esterno per rimuovere le immagini duplicate su tutti i prodotti

Obiettivo: leggere tutti i prodotti del negozio su Magento 2 e eliminare tutte le immagini duplicate per ciascun prodotto.

In Magento 2 può capitare di ritrovarsi prodotti con immagini duplicate, specialmente a seguito di una importazione di dati. Inoltre sembra che ci siano anche dei bug, o almeno ci sono stati nelle diverse versioni, che producevano questo fastidioso problema.

Quello che vogliamo fare è creare una pagina correggi_immagini.php, nella root del sito, richiamando la quale percorreremo tutti i prodotti in cerca di immagini duplicate e le elimineremo.

Come piccolo accorgimento voglio che lo script sia eseguito solo a seguito di una specifica chiamata GET sulla pagina, per esempio /correggi_immagini.php?auth=1234567890abcdefghilmnopqrstuv

Al posto di 1234567890abcdefghilmnopqrstuv raccomando di sostituire un codice sufficientemente complesso.

Nei commenti ho inserito i dettagli sullo sviluppo dello script:

Vedi articolo

[woocommerce] Disabilitare metodi di spedizione in base alla classe di spedizione

Aggiungendo un filtro a functions.php del tema attivo o in qualunque plugin attivo, possiamo escludere alcuni metodi di spedizione in base alla class di spedizione del prodotto.

Immaginiamo di aver aggiunto, tra i metodi di spedizione, qualcosa di simile (nel mio caso Corriere BRT):

E contestualmente abbiamo creato una classe di spedizione chiamata sempre Corriere BRT nel modo seguente:

A questo punto vogliamo che solo i prodotti con la suddetta classe abbiano a disposizione il suddetto metodo di spedizione, che venga invece escluso per quelli senza una classe.

Procuriamoci anzitutto l’ID della classe e quello della spedizione. Utilizzando Chrome, nel mio esempio, clicchiamo col destro sulla classe di spedizione e scegliamo Ispeziona.

Nella finestra di ispezione individuiamo il codice della classe nel modo seguente:

Nel mio caso il valore da salvare è 17834.

Adesso individuiamo l’ID del metodo di spedizione. Lo possiamo recuperare dal carrello sempre utilizzando Ispeziona su Chrome. Andiamo nel carrello dove abbiamo un prodotto con il metodo di spedizione desiderato:

Clicchiamo su Ispeziona ed individuiamo il seguente pezzo di codice:

Nel mio caso il codice è flat_rate:7

Raccolte tutte queste informazioni andiamo a modificare il file functions.php aggiungendo il filtro.

Modifichiamo opportunamente i due codici che ci interessano.

Fatto questo ci accorgeremo come il hook woocommerce_package_rates non viene chiamato sempre, ma solamente al momento in cui si aggiorna la quantità di prodotti nel carrello. Affinché la cosa funzioni correttamente dobbiamo chiamarlo sempre.

Per farlo andiamo su WooCommerce > Impostazioni > Spedizione > Opzioni di spedizione e qui spuntiamo la voce Abilita la modalità di debug

Se abbiamo fatto tutto correttamente adesso il metodo di spedizione è disponibile solo per la classe scelta.

Vedi articolo

[wordpress] Escludere pagine dalla sitemap generata da YoastSEO oppure JetPack

Sia YoastSEO che JetPack permettono di generare automaticamente delle sitemap per i contenuti del sito.

Potrebbe essere però necessario escludere alcune pagine dalla sitemap. Per esempio le pagine del carrello, del checkout e dell’account, generate da WooCommerce, comprendono il tag noindex, che le esclude dall’indicizzazione di Google per ovvie ragioni (principalmente pratiche, inutile indicizzare contenuti accessibili solo per motivi funzionali o per alcuni utenti).

In entrambi i casi, la presenza di tali pagine nella sitemap, provoca degli errori sulla Google Search Console (vengono proposti link per l’indicizzazione, che poi non possono essere indicizzati per via del tag noindex). Per risolvere simili problemi è sufficiente rimuovere le pagine coinvolte dalla sitemap.

In entrambi i casi è possibile farlo programmaticamente (per YoastSEO anche intervenendo nelle opzioni di ciascuna pagina) aggiungendo un’opportuno filtro nel file functions.php del tema (o dove si preferisce).

Per JetPack sarà sufficiente aggiungere il seguente codice:

In questo caso verranno escluse le pagine con ID 102, 103 e 104. Per trovare l’ID di un contenuto, in generale, è sufficiente controllare l’indirizzo al momento della modifica. Modificando un articolo si avrà un indirizzo del tipo post.php?post=102&action=edit

Il 102 è l’ID del contenuto.

In maniera analoga per YoastSEO è sufficiente aggiungere il seguente codice:

In entrambi i casi i contenuti con l’ID coinvolto non verranno più inseriti nella sitemap.

Vedi articolo

[php] Configurare php.ini per l’upload dei file

L’upload dei file, nel PHP, dipende da diverse parametri, alcuni diretti ed altri indiretti, configurabili nel php.ini.

Anzitutto individuiamo il file di configurazione in uso. Per farlo è sufficiente utilizzare, in una pagina php, l’istruzione phpinfo();

Otterremo un output simile a questo:

Nel mio caso specifico, sotto Plesk, il file si trova in /opt/plesk/php/7.3/etc/php.ini

In una configurazione predefinita di Ubuntu Server 19.10 avremmo qualcosa di simile invece:

Il percorso del file php.ini in questo caso è /etc/php/7.3/apache2/php.ini

Detto questo modifichiamo il suddetto file individuando le seguenti istruzioni:

upload_max_filesize

Questo è il parametro principale, quello che riguarda la massima dimensione di un file in upload. Di solito si trova impostato a 2M oppure 8M. Se volessimo consentire un upload di 20MB dovremmo metterlo a: upload_max_filesize = 20M

post_max_size

Questo parametro indica la massima dimensione dell’intestazione di POST, nel caso specifico se volessimo aumentare il valore a 20MB dovremmo digitare: post_max_size = 20M

Attenzione, perché il POST contiene non solo il file in upload, ma anche altre istruzioni. Con una dimensione di 20MB significa che il massimo file caricabile sarà probabilmente attorno ai 19MB, perché una parte del post è utilizzata per inviare anche altre istruzioni, per quanto in genere ridotte e piccole. Un’istruzione più corretta potrebbe essere: post_max_size = 21M

max_file_uploads

Questo parametro definisce invece il numero massimo di file caricabili. Di predefinito è impostato su 20, quindi si potranno caricare al massimo 20 file in una volta. Se volessimo consentire il caricamento simultaneo di 50 file, potremmo impostarlo come: max_file_uploads = 50

 

A queste, che sono le istruzioni specificatamente dedicate al caricamento dei file, se ne aggiungono altre che sono strettamente connesse.

memory_limit

Il limite di memoria allocabile dal processo di PHP per l’esecuzione delle operazioni. Nel caso di grossi caricamenti questo limite potrebbe dover essere aumentato. Di solito il valore è 128M, ovvero 128MB, se volessimo aumentare il valore a 256MB dovremmo scrivere: memory_limit = 256MB

max_execution_time

Il massimo tempo di esecuzione del processo PHP. Di predefinito è impostato su 30 secondi, il che vuol dire che se l’upload impiega più tempo il PHP chiuderà l’operazione allo scadere del limite del tempo. Possiamo aumentare questo valore, per esempio su 10 minuti (60 secondi x 10), digitando: max_execution_time = 600

max_input_time

Come prima, anche questo parametro concorre col precedente. Se il tempo massimo di esecuzione è inferiore a questo parametro il processo di input verrà comunque interrotto; viceversa se questo valore è basso l’input verrà interrotto secondo quest’ultimo parametro. Se vogliamo dare anche qui 10 minuti per il massimo tempo di input digitiamo: max_input_time = 600

 

Riassumiamo infine tutte quante le variabili assieme:

Vedi articolo

[php] Costruire un oggetto iterabile che possa essere percorso con foreach, grazie alle interfacce Iterator, ArrayAccess e Countable

Oggi propongo un semplice esercizio in PHP dove vogliamo costruire un oggetto iterabile che sia accessibile come un vettore e percorribile da foreach.

Immaginiamo di avere due classi Studente e Scuola, quello che vogliamo ottenere è il qualcosa di analogo a questo:

L’output sarà così:

in tutto ci sono 4 studenti
0 -> Squall
1 -> Zell
2 -> Rinoa
3 -> Edea

Anzitutto cominciamo costruendo la classe Studente. Questa è molto semplice e non ha nulla di particolare, la possiamo costruire come vogliamo ed in particolare, ai fini dell’esercizio, la farò con una sola proprietà e due metodi (set e get).

Adesso costruiamo Scuola implementando i metodi Iterator, ArrayAccess, Countable.

Le tre interfacce permettono di implementare diverse proprietà. Affinché l’oggetto costruito con Scuola sia percorribile dal foreach usiamo l’interfaccia Iterator.

L’interfaccia implementa i seguenti metodi astratti:

Si suppone che la nostra classe abbia una proprietà “posizione“, per cui si possa ricavare un valore da questa posizione corrente con current(). Il metodo key() dovrà restituire tale posizione corrente, next() permetterà di andare alla posizione successiva, mentre rewind() consentirà di ripartire dalla posizione iniziale. Infine il metodo valid() verificherà se nella posizione attuale esiste o meno un oggetto.

Cominciamo allora costruendo la classe nel modo seguente:

Per rendere la classe operativa aggiungiamo anche un altro paio di metodi. In particolare:

Con il controllo if( $studente instanceof Studente ) vogliamo assicurarci che l’oggetto aggiunto tramite il metodo add() sia del tipo Studente. Se il tipo non è quello giusto solleviamo un errore del tipo InvalidArgumentException dove avvisiamo l’utente.

Significa che la forma:

Produrrà un errore del tipo Fatal error: Uncaught InvalidArgumentException: l'oggetto deve essere di tipo Studente in iterator.php:92 Stack trace: #0 iterator.php(87): Scuola->erroreOggettoNonValido() #1 iterator.php(98): Scuola->add('Squall') #2 {main} thrown in iterator.php on line 92

L’operazione valida sarà invece:

A questo punto l’oggetto è già iterabile mediante foreach, che può essere chiamato nel modo seguente:

Vogliamo dare la possibilità di aggiungere gli oggetti anche alla maniera di $scuola[] = new Studente("Edea");

Per farlo implementiamo la nostra classe Scuola anche su ArrayAccess. L’interfaccia ArrayAccess richiede i seguenti metodi:

Quindi implementiamoli nella nostra classe Scuola alla maniera seguente:

Anche qui usiamo if( $value instanceof Studente ) per verificare che l’oggetto sia di tipo Studente. Nel metodo offsetGet() utilizziamo il null coalescing operator per restituire null nel caso in cui l’oggetto non esista.

A questo punto l’istruzione $scuola[] = new Studente("Edea"); diventa utilizzabile, mentre $scuola[] = "Edea"; produce il solito errore Fatal error: Uncaught InvalidArgumentException: l'oggetto deve essere di tipo Studente in...

Infine vogliamo poter usare il metodo count($scuola) sul nostro oggetto, ottenendo il conteggio di tutti gli studenti inseriti. Se lo usiamo senza ulteriori implementazioni il risultato sarebbe sempre e comunque 1.

L’interfaccia Countable richiede un unico metodo:

Implementiamolo nel modo seguente:

Probabilmente sarebbe stato più carino implementare un metodo interno alla classe, magari un contatore che tenesse conto delle aggiunte, ma ai fini dell’esercizio ci accontentiamo di chiamare count sul vettore interno degli studenti.

Fatto tutto questo vediamo il risultato finale così ottenuto:

Vedi articolo

[wordpress] Got error ‘crayon-syntax-highlighter/crayon_langs.class.php on line 340

Problema: Dopo l’aggiornamento al PHP 7.3 il plugin per WordPress Crayon Syntax Highlighter, utilizzato per evidenziare codici di programmazione, smette di funzionare e blocca la visualizzazione delle pagine nelle quali è utilizzato.

Soluzione: Modificare due file per rendere compatibile il riconoscimento per espressioni regolari con le nuove definizioni di PCRE2

L’errore che si presenta è tipo il seguente: AH01071: Got error 'crayon-syntax-highlighter/crayon_langs.class.php on line 340PHP message: PHP Warning: preg_replace(): Compilation failed: invalid range in character class at offset 4 in

Purtroppo il plugin, per quanto buono, non è aggiornato da 4 anni.

In particolare presenta problemi con l’aggiornamento del PHP alla versione 7.3, per via delle nuove definizioni PCRE2 ed in particolare proprio per la presenza di un segno – (meno), proprio come trattato nel precedente articolo.

Per risolvere il problema facciamo nel modo seguente. Posizioniamoci nella cartella del plugin /wp-content/plugins/crayon-syntax-highlighter/

Modifichiamo il file crayon_langs.class.php alla riga 340

Sostituiamo la riga con:

Modifichiamo il file crayon_formatter.class.php alla riga 118

Sostituiamo le due righe con:

Fatto tutto questo il problema sarà risolto e potremo continuare ad usare il plugin.

Vedi articolo

Differenze e novità tra PHP5 e PHP7, con esempi di programmazione

Con la scusa di un po’ di esercizio vediamo anche quali sono le principali differenze tra (l’ormai vecchio) PHP 5 e il nuovo PHP 7 (che comunque è in circolazione già da un bel po’).

1. Sintassi flessibile per Heredoc e Newdoc
2. Operatore Spaceship
3. Null Coalesce Operator
4. Virgola finale negli argomenti di funzione
5. Migrazione a PCRE2
6. Unicode Codepoint Escape Syntax
7. Chiamata di errore nella codifica JSON
8. Exceptions per i fatal errors
9. Classi anonime
10. Dichiarazione del tipo di dato restituito
11. Metodo is_countable()
12. Primi e ultimi valori e chiavi di un array
13. Il metodo Closure->call
14. Prestazioni migliorate

1. Sintassi flessibile per Heredoc e Newdoc

Nell’ultimo aggiornamento del PHP 7.3 viene introdotta la possibilità di terminare il heredoc con UNA indentazione. Sottolineo UNA perché la cosa è un po’ comica, visto che una doppia indentazione (due tabulazioni) oppure degli spazi producono comunque errore.

In sostanza prima si doveva scrivere così:

Adesso è possibile scrivere così:

Questa singola tabulazione certo non farà la felicità assoluta di nessuno, però permette di aggiungere un po’ di chiarezza al codice (sebbene personalmente continui a trovarla una novità abbastanza inutile, tale qual’è).

2. Operatore Spaceship

A differenza della precedente, questa è una novità effettivamente significativa.

Viene introdotto l’operatore <=>, chiamato spaceship, che fa le veci (quasi ma non del tutto) della funzione strcmp. Questo velocizza la scrittura e ottimizza la sintassi, riducendo così il numero di passaggi a volte necessari.

Avendo il seguente codice:

Avremo il seguente output:

a <=> b : -1
mario <=> maria : 1
marii <=> mario : -1
maria <=> mario : -1
mario <=> luigi : 1
1 <=> 2 : -1
2 <=> 1 : 1
3 <=> 3 : 0

Utilizzando invece strcmp avremmo avuto il seguente codice:

Ed il seguente output:

a <=> b : -1
mario <=> maria : 14
marii <=> mario : -6
maria <=> mario : -14
mario <=> luigi : 1
1 <=> 2 : -1
2 <=> 1 : 1
3 <=> 3 : 0

Come si può notare il comportamento non è identico, se consideriamo i valori numerici e non i segni.

Per riprodurre il comportamento dell’operatore spaceship in PHP 5 potremmo immaginare di scrivere una funzione simile a questa:

Applicandola all’elenco precedente:

Avremo gli stessi risultati di <=> in PHP 7:

a <=> b : 0
mario <=> maria : 1
marii <=> mario : -1
maria <=> mario : -1
mario <=> luigi : 1
1 <=> 2 : -1
2 <=> 1 : 1
3 <=> 3 : 0

Immaginiamo dunque di voler scrivere una funzione di ordinamento per un array. In PHP 5 avremmo potuto scrivere:

Mentre in PHP 7 possiamo sintetizzare con:

Entrambi i casi produrranno un output ordinato come il seguente:

Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 7 [5] => 8 )

Inutile dire che per entrambi gli esempi avremmo potuto incorporare direttamente una funzione anonima dentro ad usort in questo modo:

Infine nel PHP 5 l’uso dell’operatore spaceship produrrebbe un errore di questo tipo:

Parse error: syntax error, unexpected '>' in /index.php on line 16

3. Null Coalesce Operator

In PHP 7 viene introdotto il null coalescing operator ??, proseguendo così le implementazioni sull’if lineare, già introdotte nel PHP 5.3 con l’Elvis operator ?:.

In generale sappiamo che possiamo scrivere un’istruzione con if lineare (o operatore ternario) di questo tipo:

Questa istruzione equivale a scrivere:

In generale questa istruzione può essere utilizzata per riassegnare la medesima variabile in uno dei due casi. Per esempio immaginiamo di voler scrivere:

Con l’Elvis operator possiamo sintetizzare la scrittura nel modo seguente:

Quello che viene assegnato è l’argomento del test. Se l’argomento del test comprende operatori logici viene assegnato il risultato dell’operazione logica.

Per capire meglio immaginiamo di voler trovare il più grande valore tra quelli dati (ci sarebbero altri mille modi, ma per lo scopo dell’esercizio prendiamo questo):

Il risultato di questa operazione darà ovviamente come risultato 8.

Se lo riscrivessimo con l’Elvis operator potremmo avere qualcosa del genere:

Purtroppo però il risultato non sarebbe più 8, bensì 1, e questo indipendentemente dal fatto che 1 esista nell’array. E’ 1 perché 1 è true, il risultato di una delle operazioni di test. (il penultimo massimo è 8, quindi 8 è maggiore di 2? sì, vero, quindi 1!)

Praticamente serve solo quando il risultato che vogliamo valutare è tra true o false, stringa nulla o meno, ecc.

A questo si aggiunge il null coalescing operator che integra il controllo della nullità della variabile, sostituendosi alla funzione isset. Immaginiamo di avere:

Questo può diventare ora:

Il comportamento è identico. Il risultato è che le seguenti due scritture sono fondamentalmente uguali, eccetto per un dettaglio:

La prima non produce una notice, mentre la seconda ci segnala qualcosa del tipo:

Notice: Undefined index: valore in index.php on line 9

Facciamo un altro esempio con entrambe:

La prima scrittura restituisce Mario senza ulteriori errori, l’oggetto non è dichiarato, quanto l’attributo; la seconda produce ancora due notice:

Notice: Undefined variable: studente in index.php on line 15

Notice: Trying to get property 'nome' of non-object in index.php on line 15

A questo punto potremmo anche scrivere:

Per dichiarare l’oggetto laddove inesistente, mentre la seguente scrittura produrrebbe sempre una notice:

A questo punto potremmo scrivere altre due equivalenze, dal punto di vista del risultato:

Ovviamente possiamo sfruttare l’operatore per altre aggregazioni del tipo:

Dove il risultato è 42, ovvero il primo valore non null della sequenza.

4. Virgola finale negli argomenti di funzione

Adesso è possibile dimenticarsi una virgola dopo l’ultimo argomento di una funzione, senza che il PHP si agiti per questo 🙄

Mentre sia nel PHP 5 che nel PHP 7 la seguente dicitura non provocava problemi:

Provare a fare lo stesso con una funzione, che accetti argomenti predefiniti o meno, provoca un errore:

Nel PHP 5 entrambe le funzioni avrebbero prodotto un errore del tipo:

Parse error: syntax error, unexpected ')' in index.php on line 12

Personalmente non la trovo un’innovazione strepitosa, ma va bene, adesso sappiamo che c’è.

5. Migrazione a PCRE2

Il PHP utilizza in generale PCRE per l’interpretazione delle espressioni regolari. Nel PHP 7.3 è stato finalmente introdotto l’utilizzo del PCRE2 che ha aspetti un po’ più stringenti e severi sulla sintassi. Facciamo un esempio, immaginando di avere una stringa dalla quale vogliamo trovare tutte le parole, compreso il simbolo (meno) e il . (punto); nel PHP 5 entrambe le seguenti scritture sarebbero state valide:

Soprassediamo sul fatto che i caratteri speciali verranno saltati e considerati alla stregua di spazi, ma il risultato sarà qualcosa di simile a:

 

Usando la prima espressione regolare all’interno di un programma come il Notepad++ avremmo ottenuto un errore:

Mentre la seconda è valida. Adesso anche nel PHP 7.3 la seconda espressione è l’unica valida, mentre la prima non funziona producendo un errore del tipo:

Warning: preg_match_all(): Compilation failed: invalid range in character class at offset 3 in index.php on line 10

Giusto per curiosità, se si volessero prendere anche i caratteri speciali potremmo utilizzare la seguente espressione regolare:

6. Unicode Codepoint Escape Syntax

Visto che si parla di stringhe facciamo un piccolo appunto a proposito dei riferimenti ai caratteri Unicode. Adesso è possibile specificarli direttamente nelle stringhe di testo con la sintassi \u{XXX}. Maggiori approfondimenti si possono trovare qui sul sito ufficiale. Questo significa che scrivendo:

Nel PHP 5 vedremo la stringa tale e quale:

\u{202E}Testo inverso

Mentre nel PHP 7 vedremo:

‮Testo inverso

Il carattere in questione è il U+202E RIGHT-TO-LEFT OVERRIDE

Si possono usare tutti i caratteri unicode, anche quelli associati agli smile, per cui echo "\u{1F602}"; produrrà ?

7. Chiamata di errore nella codifica JSON

Adesso è finalmente possibile forzare il JSON a sollevare un errore in caso di stringhe non (de)codificabili. E’ possibile infatti scrivere nel modo seguente:

Senza l’aggiunta di JSON_THROW_ON_ERROR non ci sarebbe nessuna segnalazione di errore. Grazie a tale istruzione otteniamo invece il seguente errore fatale:

Fatal error: Uncaught JsonException: Syntax error in index.php:8 Stack trace: #0 index.php(8): json_decode('stringa JSON no...', NULL, 512, 4194304) #1 {main} thrown in index.php on line 8

8. Exceptions per i fatal errors

A proposito di errori, finalmente è stato migliorato il sistema di cattura delle eccezioni con try… catch. Primo era sostanzialmente, per farla breve, necessario chiamare throw new Exception(); per sollevare un’eccezione. Adesso è possibile intercettare anche le eccezioni di sistema. Nel caso precedente l’eccezione è intercettabile con:

Come altro esempio immaginiamo di chiamare una funzione non esistente:

Nel dobbiamo usare Error per intercettare l’errore, e mentre nel PHP 5 avremmo comunque avuto il seguente output:

Fatal error: Call to undefined function funzione() in index.php on line 9

Mentre nel PHP 7 avremmo il seguente valore, prodotto dal nostro echo:

errore: Call to undefined function funzione()

9. Classi anonime

Tra le varie novità vi è la possibilità di implementare classi anonime. Cominciamo dall’esempio più semplice:

Nel PHP 5 questo produrrebbe un errore del tipo:

Parse error: syntax error, unexpected 'class' (T_CLASS) in index.php on line 7

Alla classe anonima possono essere passati anche degli argomenti per il costruttore, nel modo seguente:

L’output invece che Mario sarà Luigi. Le classi anonime possono anche estendere altre classi, come ad esempio:

Oppure implementarle:

Senza implementare il metodo stampaNome() avremmo il seguente errore:

Fatal error: Class class@anonymous contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Studente::stampaNome) in index.php on line 11

10. Dichiarazione del tipo di dato restituito

Il PHP 7 introduce la possibilità di forzare il tipo di dato restituito da una funzione. Immaginiamo di voler scrivere una funzione somma che restituisca solamente valori interi. Nella maniera classica avremmo scritto:

Passando come argomento 2.5 e 3 il risultato sarebbe stato 5.5, un float. Per forzare l’output di un intero avremmo potuto scrivere:

In PHP 7 è possibile anche scrivere:

Sintassi che nel PHP 5 avrebbe prodotto il seguente errore:

Parse error: syntax error, unexpected ':', expecting '{' in index.php on line 7

11. Metodo is_countable()

In PHP 7 è possibile verificare se un oggetto sia “conteggiabile” ovvero sia del tipo Countable. Immaginiamo la seguente serie di istruzioni:

Essendo Studenti conteggiabile viene stampato il conteggio. Nel PHP 5 avremmo ovviamente avuto un errore del tipo:

Fatal error: Call to undefined function is_countable() in index.php on line 19

Facciamo un altro esempio di funzione implementabile su Countable e dove ci può tornare utile il nuovo metodo:

In questo caso non abbiamo bisogno di chiamare la funzione count() all’interno di public function count(), ma possiamo tenere traccia della quantità di voci aggiunte al vettore $studenti tramite un contatore interno.

12. Primi e ultimi valori e chiavi di un array

Immaginiamo di avere un array di questo tipo:

Alla maniera precedente avremmo potuto scrivere:

In questo modo avremmo ottenuto un output del genere:

primo valore: 1
prima chiave: a
ultimo valore: 100
ultima chiave: c

Questo implica anche che stiamo spostando il cursore nella posizione attuale dell’array. Se provassimo a scrivere:

Il risultato non sarebbe corretto e avremmo:

primo valore: 1
ultimo valore: 100
prima chiave: c
ultima chiave: c

Quindi questa scrittura sarebbe stata impossibile. Ora, con il PHP 7.3 è possibile scrivere nel modo seguente:

Le funzioni proposte sono attualmente: array_key_first(), array_key_last() and array_value_first(), array_value_last() anche se sono state introdotte, nel PHP 7.3 solamente quelle riguardanti le chiavi. Maggiori dettagli sulla questione qui: PHP RFC: array_key_first(), array_key_last() and array_value_first(), array_value_last()

13. Il metodo Closure->call

Nel PHP 7 viene introdotta una semplificazione nell’atto di binding delle closure.

 

Se sembra che tutti si stia dicendo cose a caso vediamo un esempio:

Notiamo che la funzione scritta su $closure va ad integrare la classe, potendo interagire con tutte le sue variabili interne anche se private.

14. Prestazioni migliorate

Infine il PHP 7 introduce notevoli implementazioni in termini di performance. Di seguito riporto i risultati di benchmark ottenuti grazie a benchmark-php su un medesimo server, ma con due diverse versioni di PHP. In particolare la versione PHP 7.3 introduce notevole stabilità nell’esecuzione e nel mantenimento delle performance.

PHP 7.3.5 PHP 5.6.40

 

Vedi articolo

[php] Modificare programmaticamente i prezzi nel carrello di WooCommerce su WordPress

Immaginiamo di voler modificare i prezzi dei prodotti su WooCommerce una volta che sono stati inseriti nel carrello. Nel mio esempio voglio aggiungere uno sconto del 50% su un prodotto quando vengono comprati almeno 2 prodotti dello stesso tipo.

Per fare questo anzitutto voglio calcolare quanto verrebbe il costo di un singolo prodotto affinché la somma di tutti i prodotti, dello stesso tipo, risulti tale che 1 solo dei prodotti sia scontato al 50%.

Ammettiamo che n sia il numero di prodotti (n ≥ 2), s lo sconto (nel mio caso 50%) e x il prezzo di ciascun prodotto. Avremo

n*x=x*s+(n-1)*x

x = x*(s+n-1)/n

Stabilito questo usiamo il hook per WooCommerce woocommerce_before_calculate_totals inserendo il nostro calcolo per ultimo (dopo tutti gli eventuali plugin).

La base del codice che vogliamo usare è la seguente:

Questa funzione può essere inserita dentro functions.php del nostro tema.

Detto questo dobbiamo anche prendere in considerazione che sul prezzo finale del prodotto potrebbero incidere ulteriori parametri (derivati magari da altri plugin) che potrebbero variare il prezzo. Per ovviare a questo problema legherò il hook alla fine di tutte le altre eventuali operazioni (da qui il valore 1000 nell’ordinamento di esecuzione del hook) e calcolerò il prezzo a partire da quello base, applicando poi il modificatore che sarebbe risultato prima del mio sconto.

La nuova funzione sarà la seguente:

Volendo calcolare il valore scontato al 50% al parametro p ho inserito il valore 0.5.

In questo modo calcoliamo il prezzo finale che dovrebbe avere ciascun prodotto, affinché risulti che la somma dei prodotti sia la somma di un prodotto scontato al 50% e di tutti gli altri a prezzo pieno (compresi gli eventuali modificatori).

Vedi articolo