====== PHP ======
PHP és el llenguatge de programació web entorn servidor més popular des de fa molts anys. La web de referència és [[http://php.net]] i on haurem de consultar de forma oficial sempre que tinguem dubtes.
{{ php.png?300 }}
Les sigles PHP ténen el què es coneix per [[definició recursiva]]. "PHP" significa, literalment, "PHP Hypertext Preprocessor".
Aquest article està pensat per a gent que coneix les bases de la programació i que s'està iniciant en l'àmbit web, pel què no ens detindrem en conceptes de variable, funció, array, diccionari/map, etc. sinó que suposem que es coneixen prèviament.
{{tag> #FpInfor #Daw #DawMp07 #DawMp07Uf1 #DawMp07Uf1 #php }}
===== Referències =====
* Web oficial: http://www.php.net
* Curs de PHP bàsic a cacauet.org: http://cacauet.org/wiki/index.php/Curs_de_PHP
* Referència PHP a W3Schools: https://www.w3schools.com/php/default.asp
* [[Apache2 en Debian/Ubuntu]] : pràctica per posar en marxa el servidor web més famós.
\\
===== Instal·lació de PHP i primeres passes =====
Treballarem PHP sobre GNU/Linux Debian/Ubuntu. Instal·lar PHP és tan fàcil i obvi com:
$ sudo apt install php
En aquest article no necessitem parar massa atenció a les versions ja que treballarem amb els bàsics del llenguatge, però si estem instal·lant programari tipus [[CMS]] i similars caldrà que revisem bé la versió instal·lada i les llibreries afegides.
PHP es pot executar de diferents maneres:
* Sobre un **servidor web**, típicament [[Apache2 en Debian Ubuntu|Apache]] o [[Nginx]]. És l'entorn més habitual de treball.
* Amb un [[https://www.php.net/manual/es/features.commandline.webserver.php|servidor web intern o embedded]] que porta incorporat el propi intèrpret de PHP. Va molt bé per fer proves i no haver d'instal·lar arxius a les carpetes de sistema on treballa Apache.
* En una **consola de PHP en mode interactiu**, es sol obrir amb ''php -a''
\\
===== Variables =====
Les variables en PHP van sempre precedides del símbol $.
PHP és un llenguatge de [[tipatge dinàmic]], el què significa que una variable pot canviar el seu tipus de dades en temps d'execució. És una característica habitual dels llenguatges interpretats (i no gens habitual en els llenguatges compilats).
Entrem en la consola en mode interactiu per fer les primeres proves amb ''php -a'':
$ php -a
Interactive mode enabled
php > $a = 1;
php > echo $a;
1
php > var_dump($a);
int(1)
php > $a = "hola";
php > echo $a;
hola
php > var_dump($a);
string(4) "hola"
php > echo gettype($a);
string
Instruccions vistes:
* ''echo''
* ''var_dump''
* ''gettype''
Respon:
* Què fa cadascuna d'elles?
* Quina diferència hi ha entre ''var_dump'' i ''print_r'' ?
\\
===== Strings =====
Els //strings// o cadenes de caràcters mereixen un parell de comentaris abans de continuar.
Per mostrar text (que és la operació més habitual en PHP ja que la seva principal missió és construir un HTML) utilitzem ''echo'' i posem el text entre cometes dobles o simples. Ambdues funcionen, però tenen efectes diferents:
* Cometes dobles: interpreten el contingut del //string// i substitueixen les variables que hi pugui haver.
* Cometes simples: no interpreten el contingut i el mostren "tal qual és".
Exemple:
php > $usuari = "Enric";
php > echo "Hola, $usuari";
Hola, Enric
php > echo 'Hola, $usuari';
Hola, $usuari
Com podem veure, un mostra el contingut de la variable (Enric) i l'altre no.
També funciona amb arrays (ho veurem més endavant).
==== Concatenació de strings ====
Podem concatenar //strings// i variables amb el caràcter punt (.)
Per exemple, el què hem fet abans ho podem fer també així:
php > echo "Hola, ".$usuari;
Hola, Enric
D'acord que es pot posar la variable dins de les cometes dobles i ens apareixerà, però sovint és més clar a l'hora de llegir el codi concatenar amb el punt i així també el //syntax highlight// de l'editor ens ressaltarà de forma més clara què estem fent.
==== Escape ====
A més, és molt comú necessitar **fer //escape// de determinats caràcters com l'apòstrof**. Si estem utilitzant cometes simples i necessitem escriure un apòstrof (és el mateix caràcter) podem escapar amb una contrabarra i es mostrarà l'apòstrof.
php > echo 'Vivim a l'Hospitalet';
php '
php ' ';
PHP Parse error: syntax error, unexpected 'Hospitalet' (T_STRING), expecting ';' or ',' in php shell code on line 1
php > echo 'Vivim a l\'Hospitalet';
Vivim a l'Hospitalet
Com podem veure, l'apòstrof em tanca el //string// i llavors em dona un error (a part de liar la consola). Si necessito un apòstrof entre cometes simples, utilitzem la contrabarra (//escape//) abans.
==== Combinació de cometes ====
Com que sovint estem construint un HTML amb PHP, es dona que per aconseguir un doc del tipus HTML ens convé utilitzar una combinació de cometes simples i dobles. Per exemple, per aconseguir això:
La forma més fàcil per fer-ho seria aquesta:
echo '';
Però si volem ficar pel mig alguna variable, les cometes simples no ens deixaran fer-ho dins del //string//. Per tant, serà més fàcil fer les cometes simples dins del HTML:
echo "";
Com alternativa, o si volem fer servir cometes simples, haurem de concatenar:
echo '';
\\
===== Servidor intern PHP =====
Ara treballarem amb el servidor intern de PHP (mes tard ja veurem com treballar amb Apache).
Crearem una carpeta ''php1'' en el nostre //home directory// on hi posarem els arxius PHP (en aquest exemple creem un arxiu ''index.php'') i posem en marxa el servidor:
$ mkdir php1
$ cd php1
$ echo "
PHP quick
" > index.php
$ php -S 0:8080
[Thu Sep 9 16:45:10 2021] PHP 7.4.9 Development Server (http://0:8081) started
...
Ara podem apuntar el //browser// al port 8080 de la nostra màquina per veure si es mostra alguna cosa:
http://localhost:8080
Per visualitzar la web cal mantenir la //shell// oberta. Si la parem, el servidor intern es pararà i no deixarem de tenir disponible la web.
\\
===== Primera pàgina PHP =====
Edita ''index.php'' i ara posa-hi aquest contingut:
En un arxiu PHP es comença escrivint en HTML
Aquesta línia l'hem escrita en PHP";
?>
Aquesta línia torna a ser HTML
Accedeix amb el navegador a ''localhost:8080'' i observa el resultat i el codi generat amb CTRL+U.
Utilitzar CTRL+U és una eina imprescindible per veure quin és el codi que hem generat finalment després de l'execució del PHP.
\\
===== Mostrar els errors del codi =====
Si introduïm errors al nostre codi no es veuran al navegador. Això és habitual ja que si la nostra web té algun error no volem mostrar-ho a l'usuari "tal qual", sinó que hauriem de fer algun post-processament del tipus captura d'excepcions, etc.
A més, mostrar els errors del nostre codi pot oferir informació interna de la nostra web que la podrien fer vulnerable a usuaris malintencionats ja que revela com està feta la web.
**Per veure els errors podem mirar la consola**. Introdueix algun error a la part PHP (per exemple, afegeix una línia amb lletres aleatòries) i visualitza per veure com va.
Si igualment vols fer mostrar els errors al //browser//, pots introduir aquestes línies a l'inici del codi PHP:
# codi PHP per mostrar els errors al browser
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
\\
===== Estructures de control =====
Les estructures principals de control son els habituals bucles i condicionals. La web de referència és http://php.net :
* [[https://www.php.net/manual/es/control-structures.for.php|for en PHP]]
* [[https://www.php.net/manual/es/control-structures.elseif.php|if en PHP]]
==== Exercicis ====
Fes els següents exercicis en PHP.
Cal que a tots els exercicis hi hagi variables per als límits (N,M).
{{ exercicis_taules_php.png }}
\\
===== Estructures de dades ======
En els llenguatges interpretats moderns com [[Python]] o [[Javascript]] es solen utilitzar dues estructures bàsiques molt importants (amb diverses variacions):
* arrays o llistes
* diccionaris o arrays associatius
==== Arrays i llistes ====
Els arrays ja sabem que son conjunts de dades estructurats de forma consecutiva. Això era veritat en llenguatges compilats com C/C++ o Java, però en PHP o Python ja no és així ben bé. La primera diferència és que els arrays de llenguatges compilats han de ser del mateix tipus de dades, i son estàtics. En canvi, **els arrays en PHP o Python poden contenir elements heterogenis (strings, sencers i floats barrejats), i que son estructures dinàmiques (tipus llista) on podem afegir i eliminar elements**.
Es pot **definir i inicialitzar un array** de diverses maneres, bàsicament aquestes:
$a = []; # array buit
$b = array();
$c = ["gos","gat"]; # array inicialitzat amb 2 elements
$d = array("gos","gat");
Prova d'inicialitzar arrays utilitzant la consola de PHP amb ''php -a'' i visualitzar els continguts amb ''var_dump''.
Per **afegir elements a un array** es pot fer amb la funció [[https://www.w3schools.com/php/func_array_push.asp|array_push]] o amb els claudàtors [ ]:
$a = ["gos","gat"];
array_push($a,"elefant");
$a[] = "jirafa";
var_dump($a);
array(4) {
[0]=>
string(3) "gos"
[1]=>
string(3) "gat"
[2]=>
string(7) "elefant"
[3]=>
string(6) "jirafa"
}
Com es pot veure, els índexs de l'array s'incrementen correlativament.
Per **esborrar un element d'un array**, es pot fer amb la instrucció ''unset'':
php > unset( $a[2] );
php > var_dump($a);
array(3) {
[0]=>
string(3) "gos"
[1]=>
string(3) "gat"
[3]=>
string(6) "jirafa"
}
Primera cosa sorprenent de PHP: **quan s'esborra un element d'un array, els índexs no es renumeren**. En aquest exemple, a l'esborrar l'element 2, els índexs que queden son 0,1,3 (sense el 2).
Si volem redefinir els índexs, ho podem fer amb la instrucció [[https://www.w3schools.com/php/func_array_values.asp|array_values()]], i el índexs tornaran a ser correlatius:
php > $b = array_values($a);
php > var_dump($b);
array(3) {
[0]=>
string(3) "gos"
[1]=>
string(3) "gat"
[2]=>
string(6) "jirafa"
}
Al tanto, que com podeu veure en realitat no es reordena l'array inicial, sinó que es crea un de nou ($b) amb els índexs ordenats.
\\
==== Diccionaris o Arrays Associatius ====
L'altra estructura de dades superutilitzada és el diccionari o array associatiu. Aquest es defineix com un array al que accedim mitjançant una clau. Per tant, **un array associatiu serà un conjunt de parells clau/valor**.
En PHP els arrays associatius es poden definir similarment a l'array posicional, però ara definint els índexs amb la fletxa (=>) i accedint amb claudàtors (tant per escriure com per llegir):
php > $sons = [ "gos" => "bup" , "gat" => "miau" ];
php > var_dump($sons);
array(2) {
["gos"]=>
string(3) "bup"
["gat"]=>
string(4) "miau"
}
php > echo $sons["gat"];
miau
I afegim elements de forma similar a Python o Javascript
php > var_dump($sons);
array(3) {
["gos"]=>
string(3) "bup"
["gat"]=>
string(4) "miau"
["vaca"]=>
string(2) "mu"
}
La //bottom line// sobre **//arrays// vs //arrays associatius// en PHP és que en realitat són la mateixa estructura de dades**, i un //array// sempre es pot tractar com a array associatiu on els índexs son la clau.
Per iterar un array associatiu sol ser més fàcil utilitzar el //[[https://www.w3schools.com/php/php_looping_foreach.asp|foreach]]// enlloc del clàssic //for//:
foreach( $sons as $animal => $so )
{
echo "El $animal fa $so. \n";
}
\\
==== Exercicis ====
=== Batalla Naval ===
Anem a fer una aproximació a un joc de batalla naval. Els típics elements de joc son:
* vaixell d'una posició: fragata
* vaixell de 2 posicions: submarí
* vaixell de 3 posicions: destructor
* vaixell de 4 posicions: portaavions
Realitza els següents exercicis:
- Utilitza l'exercici 4 dels taulells de jocs amb el nom de les files (lletres) i columnes (números).
- Crea un array amb un submarí i mostra-ho al taulell.
* Col·loca'l en una posició aleatòria cada cop que es carrega.
* Comprova que funciona en horitzontal i vertical.
* Comprova que no surt dels límits de la quadrícula.
* L'algorisme ha de funcionar amb qualsevol tipus de longitud de vaixell.
- Pensa en 2 maneres diferents per definir una partida sencera amb diversos vaixells i justifica pros i contres. En concret es recomana analitzar //array// de vaixells vs matriu de caselles.
- Crea una matriu per a la partida amb un vaixell de cada tipus (fixe) i mostra-ho al taulell.
- Omple ara la matriu amb tota una **partida amb valors aleatoris**: 4 fragates, 3 submarins, 2 destructors i 1 portaavions.
* Els vaixells han de tenir col·locació aleatòria, incloent que puguin estar en vertical o en horitzontal.
* Comprova que cada cop que recarregueu el tauler et surt una partida diferent.
* No importa si els vaixells es solapen o si surten dels límits.
- Ajusta el generador de partida anterior aplicant aquestes millores:
* Evitar que cap vaixell surti dels límits del taulell.
* Evitar que es solapin els vaixells.
* Evitar que els vaixells es "toquin" (cel·les adjacents).
\\
===== Formularis, GET, POST i PHP =====
Referències bàsiques a W3Schools:
* [[https://www.w3schools.com/html/html_forms.asp|Formularis HTML]].
* [[https://www.w3schools.com/html/html_form_elements.asp|Elements d'un formulari HTML]].
* [[https://www.w3schools.com/html/html_form_input_types.asp|Tipus de input field]].
* [[https://www.w3schools.com/php/php_forms.asp|Gestió de les dades dels formularis en PHP]]
* Per comprovar si certes variables $_GET o $_POST ens arriben, es sol emprar la [[https://www.php.net/manual/en/function.isset.php|funció isset() de PHP]]. Per exemple:if( isset($_POST["nom"]) ) {
// codi a executar aquí...
}
Altres:
* [[https://cacauet.org/wiki/index.php/Curs_de_PHP|Curs bàsic de PHP a cacauet.org]].
* [[https://www.cacauet.org/wiki/index.php/PHP_Forms|Creació de formularis GET]]. Fes la pràctica de la fórmula de resolució de l'equació de 2n grau.
* [[https://www.jose-aguilar.com/blog/controlar-array-de-checkboxes-con-php/|Checkboxes i arrays]], ideal per fer un menú d'opcions a seleccionar.
Vés a les [[https://bytes.cat/fites_daw_mp07_uf1#fita_2us_formularis_amb_get_i_post|fites sobre formularis de la UF1 de MP07 de DAW]] i realitza els exercicis.
\\
===== Arxius =====
Si volem guardar dades en arxius en PHP, disposem de diverses funcions per a realitzar aquestes operacions.
Funcions "a lo bèstia" (carreguen tot en RAM, oju peligru):
* [[https://www.php.net/manual/es/function.file.php|file()]] : carrega tot un fitxer en un array (cada línia serà un element)
* [[https://www.php.net/manual/es/function.file-put-contents.php|file_put_contents()]] : guarda les dades en un arxiu.
* [[https://www.php.net/manual/es/function.file-get-contents.php|file_get_contents()]] : carrega les dades d'un arxiu sencer sobre un //string//.
Funcions més "fines":
* [[https://www.w3schools.com/php/func_filesystem_fopen.asp|fopen]] : per obrir un arxiu. Recordeu que hi ha els modes de lectura (r), (sobre)escriptura (w) i afegir (a).
* [[https://www.w3schools.com/php/func_filesystem_fgets.asp|fgets]] : carrega 1 sola línia d'un arxiu. Cal utilitzar-la en combinació amb ''fopen''.
* [[https://www.w3schools.com/php/func_filesystem_fwrite.asp|fputs]] o [[https://www.w3schools.com/php/func_filesystem_fwrite.asp|fwrite]] (són sinònims): escriu
Si volem guardar les dades d'un array, no tindrem prou amb aquestes funcions, ja que al guardar les dades d'un array les concatena totes juntes.
Per solventar-ho i poder guardar correctament les dades d'un array, utilitzem les funcions [[https://www.php.net/manual/en/function.serialize.php|serialize]] i [[https://www.php.net/manual/en/function.unserialize.php|unserialize]].
php > var_dump($sons);
array(3) {
["gos"]=>
string(3) "bup"
["gat"]=>
string(4) "miau"
["vaca"]=>
string(2) "mu"
}
php > file_put_contents( "sons.txt", serialize($sons) );
php > $sons2 = unserialize( file_get_contents("sons.txt") );
php > var_dump($sons2);
array(3) {
["gos"]=>
string(3) "bup"
["gat"]=>
string(4) "miau"
["vaca"]=>
string(2) "mu"
}
Examina l'arxiu "sons.txt" que has creat i explica què significa cada valor que hi apareix.
\\
===== Sessions =====
Les sessions ens faciliten que cada usuari pugui disposar d'una àrea per emmagatzemar variables: la variable ''$_SESSION[]''.
Aquest mecanisme utilitza les //cookies// del navegador web per identificar l'usuari que es connecta a cada //request//.
[[https://www.w3schools.com/php/php_sessions.asp|PHP Sessions a W3Schools]].
\\
===== Més coses =====
\\
==== Carregar imatges ====
Aquí tens un [[https://pqina.nl/blog/image-upload-with-php/|tutorial per carregar imatges en PHP]].
També es poden [[https://www.php.net/manual/en/features.file-upload.multiple.php|enviar múltiples arxius]] en un sol //input field//.
- Implementa una pàgina de càrrega d'imatges al teu servidor en producció.
- Visualitza les imatges carregades.
- Afegeix un camp de descripció per a la imatge. Les imatges s'han de mostrar amb la seva descripció al costat o a sota.
- Arranja-ho perquè permeti la càrrega de vídeos.Per augmentar el límit de dades que pot carregar PHP, hauràs de modificar l'arxiu ''php.ini'' i ampliar les variables ''max_upload_size'' i ''post_max_size''.
\\
==== Enviar emails ====
Disposar d'un servidor d'email s'ha convertit en una tasca complicada degut a les grans quantitats de Spam que circulen. Disposar d'un servidor d'email que passi els controls antispam és força complicat. Podeu conèixer mes detalls a l'article [[email Linux Docker]].
Disposem, al menys, de dos maneres de fer-ho:
- Tenint un **servidor d'email local com postfix** i enviant mitjançant la [[https://www.php.net/manual/es/function.mail.php|comanda PHP mail()]].
- Utilitzant les **llibreries ''phpmailer''**: amb aquesta llibreria podem enviar mitjançant un servidor extern (caldran credencials).
\\
=== Opció 1: Servidor local ===
És important que tinguem obert el port 25 de sortida. Tots els servidors de Cloud ho estan limitant per evitar spammers, i cal demanar un permís especial perquè funcioni.
Si disposem d'aquest servidor resulta relativament senzill.
Instal·lem postfix i mailutils:
$ sudo apt install postfix mailutils
Chequejem la instal·lació enviant un email:
$ mail destinatari@email.com
Cc:
Subject: prova de correu
aqui poso el text de l'email
pot tenir diverses línies
acabem l'email amb un "." o bé amb CTRL+D
...i s'enviarà l'email. Comproveu la carpeta de Spam perquè probablement vagi a parar allà.
\\
=== Opció 2: libs PHPMailer ===
Amb aquesta llibreria podem enviar mitjançant un servidor extern (caldran credencials).
* [[https://netcorecloud.com/tutorials/send-an-email-via-gmail-smtp-server-using-php/|Enviar emails utilitzant SMTP Gmail amb PHP]].
Utilitza el tutorial indicat més amunt per enviar un email. Fes un formulari que permeti ajustar destinatari, títol i contingut del missatge.
Per carregar les llibreries al vostre codi cal canviar els ''require'' que hi ha per:
require "vendor/autoload.php";
**Utilitza l'email de l'institut**. Un Gmail normal no et permetrà enviar emails amb autenticació usuari/password (el què anomenen //"less secure apps"//), ja que no compleix amb les mesures de seguretat mínimes. De moment, a data de gener de 2023, als comptes corporatius els permeten les //less secure apps//.
\\