Jump to content

Search the Community

Showing results for tags 'Programmazione'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Argomenti
    • Windows 10 News
    • Guide e Tutorial
    • Hardware
    • Software
    • Internet
    • Telefonia
    • Videogiochi
    • Deep Web
    • Hacking
    • Cracking

Blogs

  • Guadagnare Online
  • SEO e SEM
  • Trading e Investimenti

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


About Me

Found 23 results

  1. Programmazione Funzionale Esistono tre meccanismi principali ereditati dalla programmazione funzionale: Map Filter Reduce Map Map applica una funzione func a tutti gli elementi di una input_list -> map(func, input_list) items=[1,2,3,4,5] squared=[] for i in items: squared.append(i**2) #con map items=[1,2,3,4,5] squared=list(map(lambda x: x**2, items)) -> funzione len(), lista['how', 'are', 'you'] >>> print(list(map(len, ["how", "are", "you?"]))) [3, 3, 4] Una definizione più corretta: -> map(func, *iterables) * significa che posso passare un numero x di oggetti iterabili (pari al numero di parametri che richiede la funzione) In Python 3 la funzione map ritorna un oggetto di tipo map object che è un generator object In Python 2 restituiva una lista Per ritornare una lista usare il metodo list my_pets=['alfred','tabitha','william','arla'] uppedred_pets=[] for pet in my_pets: pet_=pet.upper() uppered_pets.append(pet_) print(uppered_pets) #con map my_pets=['alfred','tabitha','william','arla'] uppered_pets=list(map(str.upper, my_pets)) print(uppered_pets) my_pets=['alfred','tabitha','william','arla'] uppered_pets=map(str.upper, my_pets) print(uppered_pets) print(type(uppered_pets)) for i in uppered_pets:print(i) ========== <map object at 0x10..> <class 'map'> ALFRED TABITHA WILLIAM ARLA >>> Esempio map con oggetti iterabili più di uno circle_areas=[3.56773, 5.57668, 4.00914 23.0101, 9.01344, 32.00013] result=list(map(round, circle_areas, range(1,7))) print(result) =========== RESTART: [3.6, 5.58, 4.009, 56.2424, 9.01344, 32.00013] >>> Filter Filter() restituisce un oggetto iteratore composto dagli elementi per i quali la funzione restituisce true richiede che la funzione restituisca valori booleani e "filtra" via gli elementi falsi filter(func, iterable) Filter vs. map A differenza di map(), è richiesto solo un iterabile L'argomento func deve restituire un tipo booleano. In caso contrario, filter restituisce semplicemente l'iterabile passato a func Poichè è richiesto un solo oggetto iterabile, è implicito che func debba accettare solo un argomento scores=[60, 90, 55, 59, 76, 70, 88, 70, 81, 65] def filtering(score): return score>70 over_70=filter(filtering, scores) over_70_list=list(over_70) print(over_70_list) print(type(over_70)) =========== [90, 76, 88, 81] <class 'filter'> >>> Se la funzione è None, viene assunta la funzione identità, ovvero vengono rimossi tutti gli elementi falsi dell'iterabile score=[60, 0, 55, 59, 76, 70, 88, 70, 81, 65] over_70=list(filter(None, scores)) print(over_70) ========== [60, 55, 59, 76, 70, 88, 70, 81, 65] >>> L'espressione filter(function, iterable) è quindi equivalente a: (item for item in iterable if function(item)) # if function is not None (item for item in iterable if item) #if function is None Curiosità: itertools.filterfalse(function,iterable) - Crea un iteratore che filtra gli elementi da iterabile restituendo solo quelli per i quali il predicato è Falso Reduce Reduce applica cumulativamente una funzione di due argomenti agli elementi di un iterabile, opzionalmente iniziando con un argomento iniziale. -> reduce(func, iterable[, initial] func è la funzione a cui viene applicato cumulativamente ogni elemento nell'iterabile Initial è il valore facoltativo che viene inserito prima degli elementi dell'iterabile nel calcolo e funge da valore predefinito quando l'iterabile è vuoto - func richiede due argomenti, il primo dei quali è il primo elemento in iterable (se initial non è fornito) - il secondo è il secondo elemento in itarable se initial è fornito, diventa il primo argomento da utilizzare e il primo elemento in iterable diventa il secondo elemento. - Reduce() "riduce" iterable in un unico valore from functools import reduce number=[3,4,6,9,34,12] def custom_sum(first, second): return first+second result=reduce(custom_sum, numbers) print(result) ========== 68 >>> Lambda functions E' possibile utilizzare le funzioni lambda Conosciute anche come anonymouse functions Sono funzioni create al 'volo' senza nome Il corpo della funzione lambda può contenere una sola espressione Non contiene l'istruzione return perchè il corpo viene automaticamente restituito -> lambda input-parameters: expression Le funzioni lambda sono trattate come le normali funzioni a livello di interprete Python Consentono di fornire una funzione come parametro ad un'altra funzione (ad esempio, in map, filter, reduce ecc.) In tali casi l'utilizzo di lambda offre un modo elegante per creare una funziona singola e passarla come parametro from functools import reduce li=[5,8,10,20,50,100] sum=reduce((lambda x, y:x+y), li) print(sum) ======== 193 >>> Lambda function e sorting # Sort case-independent L=['a', 'Andew', 'from', 'is', 'string', 'test', 'This'] L.sort(key=str.lower) # Sort by third field students=[('john','A',15), ('Jane','B',12), ('tom','B',10) students.sort(key=lambda student: student[2]) # Sort by distance from orgin, from closer to further points=[Point(1,2), Point(3,4), Point(4,1)] points.sort(key=lambda point.distanceFromOrigin()) Functools Il modulo functools fornisce strumenti per adattare od estendere funzioni ed altri oggetti chiamabili, senza riscriverli completamente Lo abbiamo usato nella reduce, introduce la classe partial Iterators Un iteratore è un oggetto che rappresenta un flusso di dati, questo oggetto restituisce i dati un elemento alla volta. Un iteratore Python deve supportare un metodo chiamato __next__() che non accetta argomenti e restituisce sempre l'elemento successivo dello stream Se non ci sono più elementi nello stream, __next__() deve sollevare l'eccezione StopIteration La funzione built-in iter() accetta un oggetto e cerca di restituire un iteratore che restituirà il contenuto o gli elementi dell'oggetto Solleva TypeError se l'oggetto non supporta l'iterazione Diversi tipi di dati built-it in Python supportano l'iterazione, come liste, stringhe e dizionari - I dizionari possono creare diversi oggetti iteratori keys(), values(), items() Un oggetto viene chiamato iterabile se è possibile ottenere un iteratore per esso Alcuni data type built-in di Python che supportano l'iterazione for element in [1,2,3]: print(element) for element in (1,2,3): print(element) for key in {'one':1,'two':2}: print(key) for char in "123": print(element) for line in open("myfile.txt"): print(line, end=' ') Iterator protocol L'istruzione for chiama iter() sull'oggetto container La funzione restituisce un oggetto iteratore (iterator object) che definisce il metodo __next__() che accede agli elementi nel contenitore, uno alla volta Quando non ci sono più elementi, __next__() solleva un'eccezione StopIteration che dice al ciclo for di terminare >>> s="abc" >>> it=iter(s) >>> it <str_iterator object at 0x00..> >>> next(it) 'a' >>> next(it) 'b' >>> next(it) 'c' >>> next(it) StopIteration Sequence unpacking support gli iteratori >>> L=[1, 2, 3] >>> iterator = iter(L) >>> a, b, c = iterator >>> a, b, c (1, 2, 3) Max(), min(), in, not in supportano gli iteratori Si può solo andare avanti in un iteratore; non c'è modo di ottenere l'elemento precedente, ripristinare l'iteratore o crearne una copia Gli oggetti Iterator possono facoltativamente fornire queste funzionalità aggiuntive, ma l'iterator protocol specifica solo il metodo __next__() Una funzione può quindi consumare tutto l'output dell'iteratore ma se devi fare qualcosa di diverso con lo stesso stream, devi creare un nuovo iteratore Generatori Due operazioni comuni sull'output di un iteratore sono: eseguire alcune operazioni per ogni elemento selezionare un sottoinsieme di elementi che soddisfano alcune condizioni List comprehensions e generator expressions sono una notazione concisa per queste operazioni Generator expressions vs. list comprehensions line_list=['line 1\n', 'line 2\n',...] #Generator expression -- returns iterator stripped_iter=(line.strip() for line in line_list) #List comprehension -- returns list stripped_list=[line.strip() for line in line_list] Sintassi: per le generation expressions usiamo le parentesi tonde () e non quadre [] Generator expressions vs list comprehension Con la list comprehension si ottiene una lista Python stripped_list è una lista contenente le righe risultanti, non un iteratore Le generator expressions restituiscono un iteratore che calcola i valori secondo necessità, senza bisogno di materializzare tutti i valori contemporaneamente Ciò significa che la list comprehension non è efficiente quando si lavora con iteratori che restituiscono un flusso infinito o una grande quantità di dati Per questi casi si usano le generator expressions La forma generica di una generator expression: ( expression for expr in sequence1 if condition1 for expr2 in sequence2 if condition2 for expr3 in sequence3 if condition3 for exprN in sequenceN if conditionN ) I generatori sono una classe speciale di funzioni che semplificano il compito di scrivere iteratori Restituiscono un iteratore che restituisce un flusso di valori Le funzioni regolari (quelle 'normali') calcolano un valore e lo restituiscono Quando si chiama una funzione regolare, essa genera un namespace privato con le sue variabili locali Quando esegue l'istruzione return, distrugge il namespace e restituisce il valore di ritorno al suo chiamante Se la funzione viene richiamata: punto 1 Qualsiasi funzione contenente la keyword yield è una funzione generatore L'istruzione yield viene usata solo quando si definisce una funzione generatore e solo nel corpo della funzione generatore Quando viene chiamata restituisce un oggetto generatore iteratore Il corpo della funzione generatore viene eseguito da una chiamata reiterata al metodo next() del generatore fino al sollevamento di un'eccezione >>> def generate_ints(N): for i in range(N): yield i La generator function restituisce un oggetto generatore che supporta l'iterator protocol Quando si esegue l'istruzione yield, il generatore genera il valore di i Yield diverso da return Quando viene eseguita l'istruzione yield, lo stato del generatore viene congelato ed il valore dello yield viene restituito alla chiamata next() Per "congelato" si intende che tutto lo stato locale viene conservato, inclusi i legami correnti delle variabili locali, il puntatore all'istruzione e lo stack di valutazione interno Al prossimo next(), la funzione procede esattamente come se l'istruzione yield fosse chiamata dall'esterno >>> gen=generate_ints(3) >>> gen <generator object generate_ints at ...> >>> next(gen) 0 >>> next(gen) 1 >>> next(gen) 2 >>> next(gen) StopIteration Esempio: leggere righe da CSV def csv_reader(file_name): fil=open(file_name) result=file.read().split("\n") return result Codice corretto ma: open() ritorna un generator object che può iterare in maniera 'lazy' file.read().split() carica tutto in memoria contemporaneamente e se il fil è molto grande può causare un MemoryError Utilizzando un generator function: def csv_reader(file_name): for row in open(file_name, "r"): yield row Si apre il file, si scorre attraverso di esse e si produce una riga (yield) Non carica tutto il file in memoria Oppure, con generator expression: csv_gen=(row for row in open(file_name)) Esempio: permutazioni Generare tutte le possibili combinazioni di stringhe alfanumeriche lunghe 8 caratteri: from itertools import permutations options='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890' possibilities=[w for w in permutations(options, 8)] Con le liste è lentissimo, meglio usare i generatori from itertools import permutations options='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890' possibilities=[w for w in permutations(options, 8)] ======= >>> possibilities.__next()__() ('A','B','C','D','E','F','G','H') >>> Passing values into a generator Per passare valori in un generatore: yield diventa un'esrepssione, restituendo un valore che può essere assegnato ad una variabile: -> val = (yield i) Utilizzare il metodo generator.send(value) def counter(maximum): i=0; while i<maximum: val=(yield i) # If value provided, change counter if val is not None: i=val else: i += 1 Se viene chiamato il metodo __next__(), yield restituisce None Generator.send(value) Riprende l'esecuzione e "invia" un valore nella funzione generatore L'argomento value diventa il risultato dell'espressione dello yield corrente Il metodo send() restituisce il valore successivo prodotto dal generatore o genera StopIteration se il generatore esce senza produrre un altro valore Quando send() viene chiamato per avviare il generatore, deve essere chiamato con None come argomento, poichè non esiste ancora un'espressione di yield in grado di ricevere il valore Altri metodi: throw, close Itertools Il modulo itertools della standard library offre molti strumenti per lavorare con gli iteratori Ad esempio chain concatena più iteratori: >>> it1=iter([1,2,3]) >>> it2=iter([4,5,6]) >>> itertools.chain(it1, it2) [1,2,3,4,5,6] ZIP(*iterables) Crea un iteratore che aggrega elementi da ciuscono degli iterabili Restituisce un iteratore di tuple, in cui la i-esima tupla contiene l'i-esimo elemento di ciascuna delle sequenze di iterabili L'iteratore si arresta quando viene raggiunta la fine dell'iterabile più breve Con un singolo argomento iterabile, restituisce un iteratore di 1 tupla Senza argomenti, restituisce un iteratore vuoto *zip 'to unzip' un zip #zip object is an iterator object x=[1,2,3,4] y=[5,6,7,8] zipped=zip(x,y) print(type(zipped)) =========== <class 'zip'> >>> zipped.__next__() (1,5) >>> next(zipped) (2,6) >>> x=[1,2,3,4] x=[5,6,7,8] # to unzip x2, y2 = zip(*zip(x,y)) x==list(x2) and y==list(y2) print(x) print(y) ======== [1,2,3,4] [5,6,7,8] >>>
  2. NumPy Numpy è una libreria open source per il linguaggio di programmazione Python, che aggiunge supporto a grandi matrici e array multidimensionali insieme a una vasta collezione di funzioni matematiche di alto livello per poter operare efficientemente su queste strutture dati Sito ufficiale: www.numpy.org Ndarray class Un oggetto ndarray è un array n-dimensionale (tensore) Simile ad una lista Python ma: - tutti gli elementi di un array devono essere dello stesso tipo (tipicamente int o float) - sono molto più efficienti e pensati per dati n-dimensioni (con n grande) Generare un array Un array viene creato tramite il metodo costruttore array() Due argomenti - una lista contenente i valori - una specifica del tipo di dato a = np.array([1,4,5,8], float) >>> import numpy as np >>> print(np.zeros(2)) [0. 0.] >>> print(np.one( (2,2) ) [[1. 1.] [1. 1.]] >>> print(np.zeros( (2,2,2) ) [[[0. 0.] [0. 0.]] [[0. 0.] [0. 0.]]] Generare random array import numpy as np print(np.random.uniform(0,10,size=5)) print(np.random.normal(1,0.2,size=5)) print(np.random.randint(0,2,size=(3,3))) [7.91700684 7.41652128 8.1393401 0.8123227 5.50427964] [1.14191823 0.89203955 1.09505607 0.8081311 0.82282836] [[ 0 0 0] [ 0 1 0] [ 0 1 1]] Matrici diagonali import numpy as np print(np.diag(np.ones(3)) [[ 1. 0. 0.] [ 0. 1. 0.] [ 0. 0. 1.]] print(np.diag(np.arange(5))) [[ 0 0 0 0 0] [ 0 1 0 0 0] [ 0 0 2 0 0] [ 0 0 0 3 0] [ 0 0 0 0 4]] Da Pandas a Numpy E' molto semplice "convertire" una pandas series o un DataFrame in un array numpy questi oggetti di Pandas sono costruiti su numpy array: il loro array sottostante è accessibile attraverso l'attributo values import pandas as pd import numpy as np iris=pd.read_csv("iris.csv") print(type(iris.PetalWidth.values)) <type'numpy.ndarray'> Metodi reshape(), ravel() La disposizione delle voci in righe, colonne, ecc. può essere modificata con i metodi: reshape() trasforma la shape dell'array ravel() trasforma in un array 1D (una copia è fatta solo se necessario) >>> a=np.arange(6).reshape((3,2)) >>> a array([[0,1], [2,3], [4,5]]) >>> x=np.array([[1,2,3],[4,5,6]]) >>> np.ravel(x) array([1,2,3,4,5,6]) >>> x.reshape(-1) array([1,2,3,4,5,6]) Iterating over arrays Oggetto iterabile nditer >>> a=np.arange(6).reshape(2,3) >>> for x in np.nditer(a): print(x,end=' ') ... 0 1 2 3 4 5 Attenzione: di default, numpy sceglie come ordine quello che rende più efficiente l'accesso all'elemento (=segue il memory layout dell'array, ovvero l'ordine con cui gli elementi sono salvati in memoria) Esempio matrice trasposta: >>> a=np.arange(6).reshape(2,3) >>> for x in np.nditer(a.T): print(x, end=' ') ... 0 1 2 3 4 5 >>> for x in np.nditer(a.T.copy(order='C')): print(x,end=' ') ... 0 3 1 4 2 5 Modificare i valori di un array Di default, l'oggetto iterabile nditer non consente la modifica dell'array (read-only object) Per modificarlo occorre usare i flag readwrite o writeonly Il nditer produrrà quindi un writable buffer array Poichè il nditer deve copiare questi dati del buffer nell'array originale al termine dell'iterzione, è necessario segnalare quando termina l'iterazione, mediante: l'istruzione with il metodo close() Una volta che uno di questi metodi è chiamato viene eseguito il write-back >>> a=np.arange(6).reshape(2,3) >>> a array([[0,1,2], [3,4,5]]) >>> with np.nditer(a, op_flags=['readwrite']) as it: for x in it: x[...]=2*x ... >>> a array([[0,2,4], [6,8,10]]) External loop In realtà con gli array numpy non è molto conveniente iterare su un singolo elemento alla volta. Per questo esistono gli external loop che lavorano su chunk di dati Forzando 'c' o 'F' otteniamo diversi external loop size >>> a=np.arange(6).reshape(2,3) >>> for x in np.nditer(a, flags=['external_loop']): print(x,end=' ') ... [0 1 2 3 4 5] >>> for x in np.nditer(a, flags=['external_loop'], order='F'): print(x,end=' ') ... [0 3] [1 4] [2 5] Broadcasting Array Iteration >>> a=np.arange(3) >>> b=np.arange(6).reshape(2,3) >>> for x,y in np.nditer([a,b]): print("%d:%d" % (x,y), end=' ') ... 0:0 1:1 2:2 0:3 1:4 2:5 Indexing Un elemento di una lista si accede: x[i][j] Un elemento di un numpy array si accede x[i,j] import numpy as np x=np.arange(9).reshape((3,3)) print(x) print(x[0,:]) #first row print(x[:,0]) #first column print(x[1:3, :])#subarray Operazioni broadcasting import numpy as np x=np.arange(5)*10 print(x) # [0 10 20 30 40] y=-x print(y) # [0 -10 -20 -30 -40] x=x+y print(z) # [0 0 0 0 0]
  3. Pandas Una libreria per la manipolazione, analisi e visualizzazione dei dati, in particolare, offre strutture dati e operazioni per manipolare tabelle numeriche e serie temporali Features: CSV (separato da virgola, TSV(separato da tab), file Excel, Database, ecc.. Sito ufficiale Pandas: www.pandas.pydata.org Esempio - Iris Dataset import pandas as pd from pandas.plotting import scatter_matrix import matplotlib.pyplot as plt df=pd.read_csv("iris.csv") scatter_matrix(df[df.Name=="Iris-virginica"]) plt.show() Pandas fornisce due tipi di dato: Series rappresentano dati 1D, come serie temporali (time series), output di funzioni ad una variabile, ecc. DataFrame rappresenta dati 2D, come un file CSV (column-separated values), un microarray, una tabella di database, una matrice, ecc. Pandas - tipi di dato Ogni colonna di un DataFrame è una serie. Ecco perchè vedremo prima come funzionano le Series La maggior parte di ciò che diremo sulle Series si applica anche ai DataFrames Series Una Series è un vettore mono-dimensionale i cui elementi sono etichettati con un indice In questo senso, la Series opera un pò come una lista (si possono accedere gli elementi in sequenza), e un pò come un dizionario (si può accedere ad un elemento tramite il suo indice, che opera come una chiave e non deve essere per forza numerico) Creazione di Series specificando dati e indici s=pd.Series([2.5,3.6,5.7,5.8], index=[0,5,15,30]) 0 2.5 5 3.6 15 5.7 30 5.8 dtype: float64 specficando dati (indici numerici impliciti partendo da 0) s=pd.Series([2.5,3.6,5.7,5.8]) 0 2.5 1 3.6 2 5.7 3 5.8 dtype: float64 passando un dizionario (le chiavi diventano gli indici e i valori i dati) s=pd.Series({"a":342, "c":245, "g":546, "t":222}) a 342 c 245 g 546 t 222 dtype: int64 se viene fornito un singolo scalare, il costruttore della serie lo replicherà per tutti gli indici s=pd.Series(3, index=range(5)) 0 3 1 3 2 3 3 3 4 3 dtype: int64 Accedere ad una Series Si può accedere ad una Series sia tramite indice (come nei dizionari), sia tramite posizione (come nelle liste) import pandas as pd s=pd.Series({"a":342,"c":245,"g":546,"t":222}) s["c"] # 245 s[0] # 342 s[-1] # 222 s[7] #IndexError: index out of bounds Gli indici sono praticamente delle etichette associate alle posizioni corrispondenti, per cui si possono usare estrarre porzioni di Series (la sotto serie va da indice iniziale a indice finale compreso) >>> s["c":"t"] >>> s[0:2] a 342 c 245 dtype: int64 E' anche possibile passare una lista di indici da estrarre >>> s[["a","g"]] a 342 g 546 dtype: int64 Se un label non è contenuto, viene sollevata un'eccezione Utilizzando il metodo get, un label mancante restituirà None o il valore predefinito specificato import pandas as pd days=["mon","tue","wed","thu","fri"] sleephours=[6,2,8,5,9] s=pd.Series(sleephours, index=days) print(s["sat"]) print(s.get('sat') KeyError: 'sat' None Metodi Head, Tail I primi n elementi possono essere estratti usando head() Gli ultimi n elementi possono essere estratti usando tail() print(s.head(2)) print(s.tail(1)) a 342 c 245 dtype: int64 t 222 dtype: int64 Operazioni su Series Le operazioni aritmetiche su una Series si applicano a tutti i suoi elementi (broadcasting) s=pd.Series({"a":342,"c":245,"g":546,"t":222}) s+1 a 343 c 246 g 547 t 223 dtype: int64 Ovviamente possiamo farle anche sul singolo elem: s['c'] += 1 s a 342 c 247 g 546 t 222 dtype: int64 Masking, filtering Anche i test logici si applicano a tutti gli elementi (il risultato si chiama maschera, mask Le maschere possono essere utilizzate per filtrare gli elementi di una serie in base a una determinata condizione print(s>=300) print(s[s>=300]) a True a 342 c False g 546 g True dtype: int64 t False dtype: bool Somma di due Series La somma tra due serie le somma elemento per elemento, allineandole per indice s+pd.Series({"a":1234,"g":3451}) a 1576.0 c NaN g 3997.0 t NaN dtype: float64 Se un indice non è presente in una delle serie, il risultato è NaN (non a number) Esiste il metodo add() per cambiare valore di default (ad esempio 0 invece di NaN) Statistiche con Series s.max() s.var() s.std() s.median() s.corr(s) # Person corr. s.corr(s, method="spearman") Plotting (matplotlib) import matplolib.pyplot as plt #line plot #bar plot s.plot() s.plot(kind="bar") plt.show() plt.show() DataFrame Un DataFrame è praticamente una tabella di oggetti eterogenei Un DataFrame ha indici sia per le righe che per le colonne index rappresenta le etichette delle righe columns rappresenta le etichette delle colonne shape descrive le dimensioni della tabella ogni colonna di un DataFrame è una Series Tutte le operazioni viste per le serie possono essere applicate a colonne estratte da un DataFrame Alcune possono essere applicate anche direttamente su un DataFrame Creazione di un DataFrame Da un dizionario di liste d={'col1':[0.5,-2.1,2.3], 'col2': [0.6,-0.1,-0.9]} df=pd.DataFrame(d,index=['row1','row2','row3]) df col1 col2 row1 0.5 0.6 row2 -2.1 -0.1 row3 2.3 -0.9 Da una lista di dizionari (notare NaN) d = [{"a":1,"b":2}, {"a":2,"c":3}, ] df=pd.DataFrame(d) df a b c 0 1 2.0 NaN 1 2 NaN 3.0 Da un dizionario di Pandas Series d={"name": pd.Series(["Mario","Luigi"]), surname: pd.Series(["Rossi","Verdi"]) } df=pd.DataFrame(d) df name surname 0 Mario Rossi 1 Luigi Verdi da un CSV Consultare documentazione metodo read_csv help(pd.read_csv) Estrazione di righe e colonne E' possibile accedere ad un estratto del DataFrame con il metodo head: df.head() E' possibile estrarre tramite indici o posizioni di riga/colonna df.loc[0] name Mario surname Rossi Name: 0, dtype: object df["name"] 0 Mario 1 Luigi 2 Marco Name: name, dtype: object df.loc[[0,1]] df.lc[0:1] name surname 0 Mario Rossi 1 Luigi Verdi df[["name","surname"]] name surname 0 Mario Rossi 1 Luigi Verdi Operazioni e statistiche Come per le Series Broadcasting Filtering Masking df=pd.DataFrame(d) print(df["name"]=="Mario") 0 True 1 False Name: name, dtype: bool print(small[["Name","PetalLength","SepalLength"]] [small.PetalLength > small.PetalLength.mean()]) Name PetalLength SepalLength 114 Iris-virginica 5.1 5.8 62 Iris-versicolor 4.0 6.0 107 Iris-virginica 6.3 7.3 Merge Il merge di DataFrames viene eseguito con la funzione merge() Merge significa che, dati due tabelle con un nome di colonna comune, per prima cosa vengono abbinate le righe con lo stesso valore di colonna; quindi viene creata una nuova tabella concatenando le righe corrispondenti Esempio, dati i seguenti due dataframe: sequences=pd.DataFrame({ "id": ["Q99697", "018400", "P78337", "Q9W5Z2"], "seq": ["METNCR", "MDRSSA", "MDAFKG", "MTSMKD"], }) names=pd.DataFrame({ "id": ["Q99697", "018400", "P78337", "P59583"], "name": ["PITX2_HUMAN", "PITX_DROME", "PITX1_HUMAN", "WRK32_ARATH"], }) Merge: inner, left, right, outer... Natural join: per mantenere solo le righe corrispondenti ai data frame, specifica l'argomento how="inner" Full outer join: per mantenere tutte le righe di entrambi i data frame, specifica how="outer" Left outer join: per includere tutte le righe del data frame x e solo quelle di y corrispondenti, specificare how="left" Right outer join: per includere tutte le righe del data frame y e solo quelle di x corisspondenti, specificare how="right" Group by Il metodo groupby permette di eseguire operazioni su un gruppo di righe >>> df=pd.DataFrame({'Animal': ['Falcon','Falcon','Parrot','Parrot'], 'Max Speed': [380.,370.,24.,26.]}) >>> df Animal Max Speed 0 Falcon 380.0 1 Falcon 370.0 2 Parrot 24.0 3 Parrot 26.0 >>> df.groupby(['Animal']).mean() Animal Max Speed Falcon 375.0 Parrot 25.0
  4. Python è un linguaggio di programmazione multi-paradigma In Python il concetto di OOP segue alcuni principi base: ereditarietà, incapsulamento, polimorfismo. Classi Un oggetto è un insieme di dati (variabili) e metodi (funzioni) che agiscono su tali dati; ogni valore è un oggetto (object.__class__); si utilizza il costrutto classe: class MyNewClass: ''' docstring della nuova classe ''' pass Una classe crea un un nuovo namespace locale in cui sono definiti tutti i suoi attributi (dati o funzioni) __doctring__: restituisce la docstring della classe pass: pass è un operazione nulla. E' utile come placeholder Non appena definiamo una classe, viene creato un nuovo oggetto classe con lo stesso nome, ci consente di accedere ai diversi attributi e di creare un'istanza di nuovi oggetti di quella classe #esempio class MyClass: "docstring della mia classe" x=5 def func(self): print("Hello") print(MyClass.x) # Output: 5 print(MyClass.func) # Output: <function MyClass.func at 0x000..> print(MyClass.__doc__) # Output: 'docstring della mia classse' Creare un nuovo oggetto nome_oggetto=nome_classe() I metodi di un oggetto sono le funzioni corrispondenti di quella classe class MyClass: "secondo esempio" x=5 def func(self): print("Hello") obj = MyClass() # create a new MyClass print(MyClass.func) # Output: <function MyClass.func at 0x000..> print(obj.func) # Output: <bound method MyClass.func of ...> obj.func() # Calling function func() Output: Hello Self e Metodi di Istanza Se eseguo l'istruzione MyClass.func(): TypeError: func() missing 1 reguired positional argument: 'self' Invece obj.func() funziona senza argomento Ogni volta che un oggetto chiama il suo metodo, l'oggetto stesso viene passato come primo argomento obj.func() <-> MyClass.func(obj) Chiamare un metodo con un elenco di n argomenti equivale a chiamare la funzione corrispondente con un elenco di argomenti creato inserendo l'oggetto del metodo prima del primo argomento E' l'argomento implicito che rappresenta l'oggetto, per convenzione lo chiamiamo self Costruttore Ci sono delle funzioni di classi che iniziano con doppio underscore __ __init__() viene chiamata ogni volta che viene istanziato un nuovo oggetto di quella classe (inizializzatore) class Studente: def __init__(self, nome, cognome): self.nome=nome self.cognome=cognome Per creare variabili d'istanza studente_uno=Studente("Mario","Rossi") studente_due=Studente("Luigi","Verdi") >>> print(studente_uno) #__main__.Studente object at 0x00..> Variabili di Classe vs. Variabili di Istanza class Dog: kind='canine' def __init__(self, name): self.name=name >>> d = Dog('Fido') >>> e = Dog('Buddy') >>> d.kind 'canine' >>> e.kind 'canine' >>> d.name 'Fido' >>> e.name 'Buddy' Se lo stesso nome di attributo si verifica sia in un'istanza che in una classe, la ricerca degli attributi da la priorità all'istanza: class Warehouse: purpose='storage' region='west' >>> w1=Warehouse() >>> print(w1.purpose, w1.region) storage west >>> w2=Warehouse() >>> w2.region='east' >>> print(w2.purpose, w2.region) storage east Variabili e metodi privati C'è una convenzione per indicare nomi che devono essere trattati come privati: __nome Il carattere di sottolineatura iniziale __ prima del nome della variabile / funzione / metodo indica che è solo per uso interno class A: def __init__(self, x, y) self.__private=x self.public=y def __prmet(self): return self.__private def pubmet(self): return self.public def ppmet(self): return self.__private, self.public >>> a=A("Mario","Rossi") >>> a.public 'Rossi' >>> a.pubmet() 'Rossi' >>> a.ppmet() ('Mario','Rossi') Se si desidera che la classe base abbia delle sottoclassi e che alcuni attributi non siano da loro utilizzati, utilizzare la denominazione con doppi __ iniziali Questo richiama l'algoritmo name mangling di Python, in cui il nome della classe è inserito nel nome dell'attributo Questo aiuta a evitare name collision degli attributi nel caso le sottoclassi inavvertitamente contengono attributi con lo stesso nome Si noti che solo il nome della classe viene utilizzato nel nome modificato, quindi se una sottoclasse sceglie sia lo stesso nome di classe che lo stesso nome di attributo, è ancora possibile ottenere collisioni di nomi. Ereditarietà (Inheritance) Definizione di una nuova classe con modifiche minime o nulle ad una classe esistente, la nuova classe è detta classe figlia (sottoclasse), quella da cui eredita è detta classe genitore (classe base) class Persona: def __init__(self, nome, cognome): self.nome=nome self.cognome=cognome class Stutente(Persona): pass class Studente(Persona): def __init__(self, nome, cognome, scuola): self.nome=nome self.cognome=cognome self.scuola=scuola Super() La funzione super permette di estendere o modificare il metodo di una classe base nella classe figlia che lo eredita class Studente(Persona): def __init__(self, nome, cognome, scuola): super().__init__(nome, cognome) self.scuola=scuola class Docente(Persona): def __init__(self, nome, cognome, materie=None): super().__init__(nome, cognome) if materie is None: self.materie=[] else: self.materie=materie Python ha due funzioni built-in: isinstance() per verificare il tipo (la classe) dell'istanza issubclass() per verificare l'ereditarietà Ritornano True o False Python supporta anche una forma di ereditarietà multipla. Una definizione di classe con più classi di base: class DerivedClassName(Base1, Base2, Base3): <statement-1> . . <statement-N> Parte da Base1 poi (ricorsivamente) nelle classi base di Base1 e, solo se non vi è stato trovato, viene ricercato in Base2, e cosi via. Overriding Una classe può avere un'implementazione differente di un metodo della classe genitore class Persona: def __init__(self, nome, cognome): self.nome=nome self.cognome=cognome def stampa(self): print('genitore') class Studente(Persona): def __init__(self, nome, cognome, scuola): super().__init__(nome, cognome) self.scuola=scuola def stampa(self): print("sottoclasse") >>> Mario=Studente("Mario","Rossi","Dibris") >>> Mario.stampa() # Studente.stampa(Mario) sottoclasse Metodi di Classe I metodi degli oggetti che abbiamo visto finora vengono chiamati attraverso il nome dell'istanza della classe (oggetto), che viene passato come parametro self all'interno del metodo. I metodi di classe vengono invece chiamati direttamente dalla classe che viene passata come parametro cls all'interno del metodo, cls, come self, è semplice convenzione, si usa il decoratore @classmethod Generalmente questi metido servono per istanziare una nuova istanza di classe, passando dei parametri diversi rispetto a quelli richiesti dal costruttore. class Rectangle: def __init__(self, width, height): self.width=width self.height=height def area(self): return self.width * self.height @classmethod def new_square(cls, side_length): return cls(side_length, side_length) square = Rectangle.new_square(5) print(square.calculate_area()) Creiamo una classe per creare un dizionario per ogni utente, ed una sottoclasse per creare un dizionario con più informazioni Facciamo finta che il e il cognome siano dati come string unica (es 'Paolo-Rossi') *args permette di passare 0 o un numero arbitrario di parametri alla funzione class Crea_profilo: def __init__(self, name, surname): self.name=name self.surname=surname def crea(slef): return {"Nome":self.name,"Cognome":self.surname} @classmethod def from_string(cls, string_persona, *args): nome, cognome, = string_persona.split("-") return cls(nome, cognome, *args) class Crea_profilo_età(Crea_profilo): def __init__(self, name, surname, age): super().__init__(name,surname) self.age=age def crea(self): return {"Nome":self.name, "Cognome":self.surname, "Età":self.age} #overriding >>> persona1=Crea_profilo("Mario","Rossi") >>> persona2=Crea_profilo.from_string("Paolo-Verdi") >>> persona3=Crea_profilo_età.from_string("Luigi-Giallo",54) >>> print(persona1.crea()) {'Nome': 'Mario', 'Cognome': 'Rossi'} >>> print(persona2.crea()) {'Nome': 'Paolo', 'Cognome': 'Verdi'} >>> print(persona3.crea()) {'Nome': 'Luigi', 'Cognome': 'Giallo','Età':54} Metodi Statici I metodi statici si richiamano senza creare un'istanza della classe e pertanto non ricevono un parametro self Non possono accedere alla proprietà della classe Per i metodi statici si usa il decoratore @staticmethod class Dates: def __init__(self, date): self.date=date def getDate(self): return self.date @staticmethod def toDashDate(date): return date.replace("/","-") date=Dates("15-12-2016") dateFromDB="15/12/2016" dateWithDash=Dates.toDashDate(dateFromDB) if (date.getDate()==dateWithDash): print("Equal") else: print("Unequal") Overloading degli operatori Python consente di cambiare la definizione degli operatori predefiniti quando applicati a tipi definiti dall'utente class Punto: ... def __add__(self, AltroPunto): return Punto(self.x + AltroPunto.x, self.y + AltroPunto.y) >>> P1=Punto(3,4) >>> P2=Punto(5,7) >>> P3=P1+P2 >>> print P3 (8,11) L'espressione P1+P2 è equivalente a P1.__add__(P2) Dunder Methods Molto utili perchè garantiscono il compartimento polimorfico degli operatori __init__ e __adds__ sono metodi speciali >>> 5+5 10 >>> "Py"+"thon" 'Python' >>> int.__add__(5,5) 10 >>> str.__add__("Py","thon") 'Python' Tanti altri metodi speciali: __new__, __del__, __str__, __bool__, __sub__, __eq__ (uguale a), __ne__ (diverso da), __getitem__ (object[item]), __setitem__ (object[item]=value) ecc. Per ogni classe posso definirli in modo diverso Per maggiori info consultare la documentazione di Python! Iterators Per la maggior parte degli oggetti container abbiamo fatto il for-loop: for element in [1,2,3]: print(element) for element in (1,2,3): print(element) for key in {'one':1,'two':2} print(key) for char in "123" print(char) for line in open("myfile.txt"): print(line, end='') Iterator protocol L'istruzione for chiama iter() sull'oggetto container La funzione restituisce un oggetto iteratore (iterator object) che definisce il metodo __next__() che accede agli elementi nel contenitore, uno alla volta Quando non ci sono più elementi, __next__() solleva un'eccezione StopIteration che dice al ciclo for di terminare; funzione integrata next() >>> s="abc" >>> it=iter(s) >>> it <str_iterator object at 0x0..> >>> next(it) 'a' >>> next(it) 'b' >>> next(it) 'c' >>> next(it) StopIteration Usare gli iteratori con le classi class Reverse: """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data=data self.index=len(data) def __iter__(self): return self def __next__(self): if self.index==0: raise StopIteration self.index=self.index-1 return self.data[self.index] >>> rev=Reverse('spam') >>> iter(rev) <__main__.Reverse ojbect at 0x0..> >>> for char in rev: print(char) m a p s Moduli (librerie) I moduli sono dei file usati per raggruppare costanti, funzioni e classi Ci consentono di suddividere e organizzare meglio i nostri progetti Python include già una lista estensiva di moduli standard (anche conosciuti come standard library) import nome_modulo #esempio import random Possiamo usare le funzioni dir() e help() per esplorare i contenuti del modulo Importare i moduli import modulo #importare intero modulo from modulo import nome #importare una costante o una funzione specifica import modulo as mio_nome #rinominare il modulo >>> import random as rdm >>> rdm.randint(1,100) 41 from modulo import #importa tutto il modulo Creare un modulo Qualsiasi file con estensione.py può essere sia eseguito che importato In Python non esiste una vera distinzione tra modulo e 'main' Per creare un modulo: basta scrivere un normalissimo script python quindi salvato con estensione .py # operazioni.py def somma(x,y): return x+y def sottrazione(x,y): rturn a-b Per importarlo in un altro programma: import operazioni Package Python offre un ulteriore livello di organizzazione: i package. Un package è una raccolta di moduli, che in genere corrisponde alla directory che li contiene File vuoto __init__.py
  5. Dopo l'introduzione di Python nella prima lezione, ora proseguiamo con la lezione due e vediamo i tipi di dato. Tipi Sequenza Stringhe Liste Tuple Buffer oggetti range Liste Le liste sono sequenze mutabili, utilizzate per archiviare raccolte di oggetti (non per forza dello stesso tipo) - [1, 2, 3] è una lista - ['Pippo', True, 3] è una lista Una lista è una sequenza di oggetti ordinati Gli oggetti possono essere di qualsiasi tipo I valori sono detti elementi Gli elementi della lista sono racchiusi tra parentesi quadrate, e separati da virgole. [1,3,5,7,11,13] lista numeri interi ["Laura","Luca"] lista stringhe ["Laura",15,2.5,True] lista eterogenea [] lista vuota [3,[6,9,12]] lista contenente lista a=[1,3,7,9] variabile a contiene lista L'elemento in posizione pos di una lista si indica con [pos] Le posizioni si chiamano anche indici a[2] La prima posizione è la posizione 0: a[0] Se cerchiamo di accedere ad una posizione fuori dalla lista viene segnalato un errore a[90] Per stampare una lista intera: print(a) Con indice negativo si parte dal fondo. [-1] La lista vuota è valutata False Le liste sono mutabili (possono cambiare, aggiungere e cancellare/modificare elementi) Operazioni len() restituisce la lunghezza della lista + concatena due liste * int ripete la lista un certo numero di volte [ : ] estrae una porzione da una lista in verifica l'appartenenza di un elemento a una lista lista=['x','y','z'] lista[0]= 42 print(lista) stampa: [42,'y','z'] lista[1:1]=[5] print(lista) stampa: [42,5,'y','z'] lista[2:3]=[] print(lista) stampa: [42,5,'z'] #slice operator >>>mylista=["A","B","C",23,["A"]] >>>mylista[:] ["A","B","C",23,["A"]] >>>mylista[2:] ["C",23,["A"]] >>>mylista[:5] ["A","B","C",23,["A"]] >>>mylista[1:2] ["B"] Aggiungere un elemento In una lista, l'assegnazione di un valore ad un indice fuori dimensione genera un errore (si deve usare append) >>>L = ["a","b","c"] >>>L[3]="d" #errore >>>L.append("d") ok! lista.append(elem) aggiunge elem alla fine della lista lista.remove(elem) trova e rimuove elem dalla lista; lista.pop() rimuove e restituisce l'ultimo elemento della lista lista.clear() rimuove tutti gli elementi della lista del lista[-2] cancellare un elemento come pop del lista cancella la variabile lista Se assegniamo ad una variabile una variabile che contiene una lista, le due variabili indicano proprio la stessa lista b=a - se modifico l'una anche l'altra viene modificata per fare una copia senza "unificare" le liste, possiamo copiarne il contenuto c=a[:] Pila (stack) I metodi delle liste rendono molto semplice l'uso di una lista come una pila, in cui l'ultimo elemento aggiunto è il primo elemento recuperato (last in, first out) Per aggiungere un oggetto in cima alla pila: append(i) Per recuperare un oggetto dalla cima della pila: pop() >>> stack = [3,4,5] >>> stack.append(6) >>> stack.append(7) >>> stack [3,4,5,6,7] >>> stack.pop() 7 >>> stack [3,4,5,6] >>> stack.pop() 6 >>> stack [3,4,5] Coda (queue) E' anche possibile utilizzare una lista come una coda (first in, first out) Tuttavia, le liste non sono efficienti per questo scopo. append/pop sono veloci perchè aggiungono un elemento alla fine della lista. Ma per le code occorre fare inserimenti o rimozioni all'inizio della lista. Per implementare una coda: collections.deque, append e pop veloci da entrambe le estremità. >>> from collections import deque >>> queue = deque(["Eric","John","Micheal"]) >>> queue.append("Terry") >>> queue.append("Graham") >>> queue.popleft() 'Eric' >>> queue.popleft() 'John' >>> queue deque(["Micheal","Terry","Graham"]) List Comprehension La lista comprehension permette di trasformare e/o filtrare una lista, è una scrittura elegante e compatta. Data una lista qualungue lista_originale, posso creare una nuova lista che contiene solo gli elementi che soddisfano una certa condizione: lista_filtrata = [elemento for elemento in lista_originale if condizione(elemento)] #esempio numeri=range(10) numeri_pari = [n for n in numeri if n%2==0] print(numeri_pari) Tuple I tuple sono anche essi degli elenchi di valori indicizzati Sono sequenze immutabili (una volta creati sono immutabili), una lista di valori separati da virgola, i valori sono scritti tra parentesi tonde () 1,2,3 è una tupla (1,2,3) è una tupla a=(1,2,3) -> a[0] è 1 Tale immutabilità non si applica ai contenuti della tupla, per cui i suoi oggetti possono essere modificati se mutabili t=(12, 'abc', [1,2,3,4]) >>> t[1][2]='d' Creare una Tupla con il metodo built-in tuple() >>> t = tuple() >>> print t () Se l'argomento è una sequenza (stringa, lista o tupla) il risultato è una tupla con gli elementi della sequenza: >>> t = tuple('lupins') >>> print t ('l','u','p','i','n','s') Unpacking Arguments (funziona anche con le liste) a=(1,2) x,y=a print(x) -> 1 print(y) -> 2 Tuple con un singolo elemento occorre aggiungere una virgola finale La virgola è necessaria altrimenti Python tratterebbe la singola tupla come una stringa qualunque Operazioni len() lunghezza della tupla + concatenazione di due tuple .count() conteggio di un elemento [:] slice operator list() conversione da tuple a lista Range Range rappresenta una sequenza immutabile di numeri ed è comunemente usato nei circli for per eseguire il codice del ciclo per un certo (specifico) numero di volte. range(10) fino a (escluso) range(0,10) da (incluso) range(0,55,5) passo for i in range(11): print(i) #tabellina_del_cinqui=range(0,55,5) Il vantaggio del range rispetto ad una lista è che un oggetto di tipo range occupa sempre la stessa quantità di memoria, indipendentemente dalla dimensione dell'intervallo che rappresenta, memorizza solo i valori di inizio, arresto e passo; calcola i singoli item solo quando è necessario; se non devo lavorare su una determinata lista ma mi serve ciclare su una sequenza a caso è meglio usare range. Stringhe In Python è possibile accedere agli elementi di una sequenza usando la sintassi sequenza[indice], questo restituirà l'elemento in posizione indice. Il primo elemento ha sempre indice 0. >>> s = 'Python' >>> s[0] #elem in posizione 0 'P' >>> s[2] #elem in posizione 2 't' >>> s[-1] #elem in posizione -1 'n' #slicing >>> s[0:2] 'Py' >>> s[4:] 'on' #contenimento >>> 'P' in s True >>> 'x' in s False La funzione built-in len() può essere usata per ottenere il numero di elementi in una sequenza >>> len('Python') 6 Metodi list(), tuple() Il metodo list() prende sequence types e li converte a lista >>> my_tuple=1,3,4,5 >>> my_list=list(my_tuple) >>> print(my_list) [1,3,4,5] >>> my_string="Pippo" >>> my_list=list(my_string) >>> print(my_list) ['P','i','p','p','o'] >>> my_tuple=tuple(my_list) >>> print(my_tuple) (,'P','i','p','p','o') Mapping types (dizionario) I mapping sono oggetti mutabili, al momento esiste solo un tipo di mappatura standard, il dizionario. Una mappatura tra un insieme di chiavi e un insieme di valori. Ogni chiave (key) è mappata su un valore (value) L'associazione di una chiave e un valore viene chiamata coppia chiave-valore (key-value) I dizionari (dict) sono un tipo built-in, mutabile e non ordinato che contiene elementi (items) formati da chiave e valore I dizionari vengono definiti, elencando tra parentesi graffe {} Una serie di elementi separati da virgole, dove ogni elemento è formato da una chiave e un valore separati da due punti : Dizionario vuoto è False A differenza delle liste se si assegna un valore ad una chiave non presente, la coppia chiave:valore viene aggiunta al dizionario Per inserire un nuovo elemento (chiave-valore) nel dizionario my_dict: my_dict['Pippo']=23 #chiave Pippo e valore 23 >>> print(my_dict) {'Pippo':23} Metodi: keys() elenco contenente le chiavi del dizionario values() elenco di tutti i valori nel dizionario items() elenco contenente una tupla per ciascuna coppia di valori chiave len() numero di coppie chiave-valore >>> d={"a":0, "b":1} >>> d.items() dict_items([('a',0),('b',1)]) >>> type(d.items()) <class 'dict_items'> >>> t=tuple(d.items()) >>> t (('a',0),('b',1)) get() valore della chiave specificata update() aggiorna il dizionario con le coppie chiave-valore specificate pop() rimuove elemento con chiave specificata popitem() rimuove ultima coppia chiave-valore clear() rimuove tutti elementi dal dizionario A differenza delle sequenze, che sono oggetti iterabili che supportano l'accesso agli elementi mediante indici interi, i dizionari sono indicizzati da chiavi >>> a_dict={'color':'blue','fruit':'apple','pet':'dog'} >>> for key in a_dict: print(key) color fruit pet Per iterare: .items(), .keys(), .values() Una funzione hash è una funzione che prende un valore (di qualsiasi tipo) e ritorna un intero. I dizionari usato questi interi, chiamati hash values, per salvare e ricercare le coppie key-value Le chiavi (keys) devono essere di tipo 'hashable': il valore hash non può cambiare mai Una lista può essere un valore(value) di un dizionario {1: ['a','p','t','o'], 2:['r']} Le chiavi devono essere immutabili Dict Comprehension dictionary = {key:value for vars in iterable} #esempio original_dict={'Jack':38,'micheal':48,'guido':57,'john',33} even_dict={k:v for (k,v) in original_dict.items() if v%2==0} print(even_dict)
  6. Data Science La scienza dei dati studia i metodi per estrarre la conoscenza dei dati provenienti da diverse sorgenti: Dati aziendali Web (Social Network Analysis, Marketing) e Mobile (Context Aware Computing) Immagini e Video (sorveglianza, applicazioni mediche, ecc) IoT (sensori, ecc), Industry 4.0 L'obiettivo è la creazione di prodotti e servizi basati sull'estrazione di conoscenza dai dati immediatamente utilizzabile nei processi decisionali Big Data Si parla Big Data quando si ha a che fare con grandi quantità di dati La creazione di dati sta seguendo un processo esponenziale: nell'anno 2020 il volume totale di dati creati nel mondo è stato di più di 40 zettabyte (ZB), vale a dire 40 trilioni di gigabyte Si prevede che entro il 2025 il volume dei dati arriverà fino a 163 ZB (es. rapport Garante Privacy) Volume: dimensione dei dataset (oltre le capacità degli odierni DBMS) Velocità: rapidità con cui i dati arrivano e dono essere elaborate (streaming, real-time) Varietà: tipologia di dati e sorgenti semi-strutturati (XML, tweets, ...) destrutturati (documenti, pagine web) Veridicità: le sorgenti dei dati non sono controllate Variabilità: variazioni sia nella struttura dei dati che nella semantica sottostante; Valore: potenzialità dei dati in termini di vantaggi competitivi raggiungibili con la loro analisi Volume e Velocità sono ancora considerate di gran lunga le caratteristiche più rilevanti nella gestione dei Big Data La Scalabilità è al cuore delle nuove tecnologie che ci si attende in un futuro prossimo per affrontare le sfide tecnologiche poste dai Big Data Infrastrutture di calcolo: - Cloud Computing (Docker, Servizi, Data Center, ecc.) - Edge/IoT Computing - High Performance Computing Data Science e Linguaggi di programmazione: R, Julia, Python, C++, Javascript, Scala Professioni: Data Scientist - cos è, cosa fa e quanto guadagna? Data Engineer Data Analyst Data Protection Officier Python Pagina ufficiale: www.python.it Installazione e download: www.python.org/downloads PIP: www.pypi.org/project/pip Attraverso pip si possono installare pachetti facilmente usando pip install package-name Jupyter: www.jupyter.org Per usare Jupyter Notebook usare il comando jupyter notebook Colab: sono jupyter notebook su google cloud accessibili con le proprie credenziali google su colab.research.google.com Anaconda: www.anaconda.com Usata moltissimo per statistica e in data science Python nasce nel 1991, ora alla versione 3 uscita nel 2008, linguaggio semplice, intuitivo e potente, facilmente comprensibile, come l'inglese parlato in grado di consentire tempi di sviluppo brevi, open source con partecipazione collettiva al suo sviluppo. Python è oggi uno dei linguaggi più diffusi e più usati per la sua facilità di utilizzo. Python è un linguaggio di programmazione ad alto livello, è un linguaggio interpretato, ovvero le istruzioni sono eseguite da un interprete e permette di eseguire dirottamente il codice sorgente che scriviamo. Python è detto anche "interattivo": possiamo scrivere le istruzioni dal prompt dei comandi senza la necessità di creare un file sorgente Interprete Python Python è considerato un linguaggio interpretato, offre due modalità per usare l'interprete: Interactive mode Script mode Se lanciamo il comando python da riga di comando, in in ambiente Windows che Linux, viene mostrato un nuovo prompt caratterizzato da 3 caratteri di maggiore >>> (interprete interattivo) L'interprete interattivo è in grado di leggere e valutare man mano le espressioni inserite dall'utente, è anche possibile eseguire script contenenti sequenze di istruzioni Python, digitando il comando: python nome_script.py IDLE Per la modalità interattiva: Python Shell Disponibile anche online: www.python.org/shell IDLE (Integrated Develpment and Learning Environment): ambiente visuale che permette di modificare, eseguire, e fare il debug di programmi Python da un'unica interfaccia visuale Python come calcolatrice Un'istruzione è un operazione che l'interprete di Python è in grado di eseguire Usando Python come calcolatrice viene stampato a video il valore dell'espressione 2+2 4/2 4//2 divisione intera 4%2 modulo (resto della divisione) 3**2 elevamento a potenza (4-2)*3 precedenza tra operatori e parentesi Variabili Python è tipizzato dinamicamente controlla i tipi solo immediatamente prima dell'esecuzione delle istruzioni tutte le variabili sono implementate con puntatori Non occorre dichiarare le variabili prima di usarle I nomi delle variabili sia lettere che numeri ma devono iniziare con una lettere oppure con un "_"; possono contenere sia lettere maiuscole che minuscole e tiene in conto della differenza (case sensitive) (a!=A) <variabile>= <espressione> - Alla variabile che compare alla sinistra dell'= viene assegnato il valore ottenuto dalla valutazione dell'espressione; - L'istruzione di assegnazione non produce risultati visibili (cioè se la inviate per esecuzione all'interprete interattivo non vi viene "risposto" nulla) x=7 y=3.14 z=x+y s="ciao" I dati (valori) sono di tanti tipi diversi Dal tipo del dato dipendono le operazioni che possiamo fare con esso 8/4 ok "ciao"/2 no Tipi Semplici: Booleani (valore di verità): True e False bool Numeri interi int Numeri in virgola mobile (metodo di rappresentazione approssimata dei numeri reali) float Caratteri e Stringhe (sequenze di caratteri che formano un testo) Una string può essere una stringa di lettere, numeri e simboli. Le stringhe sono racchiuse tra '' o tra "" str x=7 x="7" x=7.0 print(8+4) vs. print("8+4") "ciao"*2 -> "ciaociao" "Py"+"thon" -> "Python" In Python le variabili assumono il tipo del valore che viene loro assegnato: numero, carattere o serie di caratteri, e lo mantengono fino a quando non viene loro assegnato un valore di tipo diverso #Quindi si potrebbe fare: x="ciao" x=5 In Python: def massimo(x,y): if x>y: return x else: return y può calcolare il massimo tra due numeri interi, due numeri reali, due stringhe, ecc.. Print L'istruzione di stampa print permette di visualizzare il contenuto delle variabili sullo schermo print(x) print("ciao") print(7+2) print("5+5 fa ", 5+5) Type La funzione type restituisce il tipo di un valore, di una variabile o di una espressione type(x) type(2) type('ciao') type(1==5) Operatori di Confronto == uguale a != diverso da < minore <= minore o uguale a > maggiore di >= maggiore o uguale a Operatori booleani and ritorna True se entrambi sono veri or ritorna True se almeno uno è vero not ritorna False se è vero, True se è falso Python Assegnazione Multipla Con l'assegnazione multipla ottengo lo scambio dei valori: a, b = b, a Input L'istruzione input (prompt) permette di acquisire valori da tastiera x=input("inserisci un valore") >>> Inserisci un valore 9 enter N.B: il valore viene acquisito sempre come string!! convertire il tipo con le funzioni int(), str()... numero= int(input('inserisic un numero:')) print(numero+7) numero=float(input('inserisci l importo in euro:')) print(numero) numero=str(numero) print(numero) Script mode Per eseguire programmi con sequenze di istruzioni usiamo la modalità script python nome_script.py Nome programma: HelloWorld.py print('Hello World') per eseguirlo da terminale: python HelloWorld.py per eseguirlo da IDLE: Run -> Run Module (F5) Commenti # tutta la riga commentata I commenti non hanno effetto sul programma (l'interprete ignora la linea commentata #assegno a b il valore 7 b=7 Commenti su più righe """ commento dentro """ Istruzioni condizionali if <condizione>: <istruzione> if x==2: print('x è uguale a 2') Se x è uguale a 2 viene effettuata la stampa, altrimenti non fa nulla. Indentazione Le istruzioni nel corpo devono essere "rientrate" cioè stare più all'interno/più a destra della riga che contiene l'if Si dice che devono essere "indentate" La prima istruzione che non è più "indentata" segnala la fine del blocco di istruzioni che devono essere eseguite se la condizione è soddisfata Se il corpo è costituito da una sola istruzione può essere scritto sulla stessa riga (come negli esempi precedenti) x=int(input('inserisci un numero')) if(x==5): print('sono dentro if') print('sono ancora dentro if') print('sono fuori if') If-else età=int(input('inserisci la tua età')) if età >= 18: print('sei maggiorenne') else: print('sei minorenne') Cicli I cicli sono usati per eseguire azioni ripetitive Ci sono due tipi di cicli: while: usato quando non si sa a priori il numero esatto di volte che una azione deve essere ripetuta for: quando si sa in anticipo quante volte si dovrà ripetere l'azione While Ripete le istruzioni nella sequenza fino a quando la condizione è soddisfata while<condizione>: <sequenza di istruzioni> x=10 while(x>0): print(x) x=x-1 print("0! sono fuori dal ciclo") For Assegna alla variabile il primo elemento della sequenza Esegue le istruzioni nel corpo Fintantoché ci sono elementi nella sequenza assegna alla variabile l'elemento successivo e torna al passo 2. Spesso la lista che si usa nel for è generata dalla funzione range: for <variabile> in <sequenza>: <sequenza di istruzioni> #stampare i numeri tra 0 e 10 for i in range(11): print(i) #stampare i numeri tra 1 e 10 for i in range(1,11): print(i) Break Se eseguo l'istruzione break dentro un ciclo while o for, "uccido" il ciclo e ne esco immediatamente Continue Idem per continue, prosegue al passo successivo. For/Else I cicli for hanno anche una clausola else La clausola else viene eseguita dopo il completamento normale del ciclo. Ciò significa che il loop non ha riscrontrato un'istruzione break for item in container: if (search_something(item): #Found it! process(item) break else: #Didn't find anything... not_found_in_container() Esempi: #!/usr/bin/env python # coding: utf-8 # **** Jupyter Notebook con esempi introduttivi **** # In[ ]: print("Hello world") # In[ ]: print("Espressioni",2,4/2,5//2,5%2,3**2,(4-2)*3) # In[ ]: x=7 y=3.14 z=x+y s="ciao" b=(1 == 2) b1=(1 <= 2) print(x,y,z,s,b,b1) x="python"+"3" print(x,type(x)) print(y,type(y)) print(s,type(s)) print(b,type(b)) print(b1,type(b1)) # In[ ]: def massimo(x,y): if x>y: return x else: return y print(massimo(12,15)) print(massimo("ciao","roma")) print(massimo(3.4,6.7)) # In[ ]: x=10 y=11 x ^= y y ^= x x ^= y print(x,y) # In[ ]: x,y=y,x print(x,y) # In[ ]: x=int(input('inserisci un numero')) if(x==5): print('sono dentro if') print('sono ancora dentro if') print('sono fuori if') # In[ ]: x=int(input('inserisci un numero')) if(x==5): print('sono dentro if') print('sono ancora dentro if') print('sono fuori if') # In[ ]: x=int(input("Inserisci un numero")) if x==0: print("numero 0") elif x==1: print("numero 1") elif x==2: print("numero 2") else: print("Un altro numero") # **** Costrutti **** # In[ ]: x=10 while(x>0): print(x) x=x-1 print("0! Qui sono fuori dal ciclo") # In[ ]: while True: print("Hello, World!") print("Qui") # In[ ]: for i in range(10): print("A"+str(i),end=", ") print("A10.") # In[ ]: for a in range(1,11): for b in range(1,11): print(a*b) # In[ ]: for a in range(4): for b in range(4): print("*",end=' ') print("\n") # In[ ]: for i in range(2): x=int(input()) if (x>10): print("Trovato!") break else: print("Niente da fare") # In[ ]: for i in range(2): for j in range(2): x=int(input()) if (x>10): print("Trovato!") break else: continue break else: print("Niente da fare") print(i,j) # **** Strutture dati: liste e tuple ****
  7. Per trovare la propria directory nel server di solito possiamo usare queste due funzionalità di javascript $_SERVER["DOCUMENT_ROOT"]: // var/www/html dirname(__FILE__): /chroot/home/S00000/public_html JSON Formato di interscambio Acronimo di JavaScript Object Notation Rappresentazione di un oggetto mediante una stringa Formato interoperabile per serializzare oggetti, non è limitato a JavaScript (es. esistono serializzatori JSON per gli oggetti .NET) Si tratta di un formato usato per il trasferimento dei dati attraverso la rete I file JSON hanno estensione .json MIME type "application/json" JSON supporta i seguenti tipi di dato . string, number, object, array E i letterali . true, false, null Le stringhe devono essere delimitate da " ... " mentre in JavaScript si può anche usare ' ... ' //invalid JSON in RFC {"username": 'ribba'} //solo doppi apici {"price": OxFF} //si possono usare solo cifre decimali I dati sono espressi come: - coppie "nome" : "valore" - separate da virgola , Gli oggetti sono racchiusi in { ... } - es.: {"nome":"Mario", "cognome":"Rossi"} Gli array sono racchiusi in [ ... ] - es.: [ {"nome":"Mario", "cognome":"Rossi"} {"nome":"Anna", "cognome":"Bruni"} ] Ogni dichiarazione valida in JSON è anche valida in JavaScript Per trasformare un testo JSON in un oggetto: JSON.parse(json_str) converte una string JSON in un oggetto Esiste anche la funzione JSON.stringify(json_obj) che converte un oggetto JavaScript in una string JSON eval(json_str) //DEPRECATA valuta o esegue quanto passato come parametro AJAX Facciamo tramite client una richiesta HTTP ad un server, il server manda in esecuzione lo script, eventualmente interagisce con il database, produce una risposta che è una pagina html con incluso il foglio di stile e incluso javascript. Con Ajax cambia un pochino la situazione, possiamo fare lo solite richieste HTTP, ma poi quando siamo dentro la pagina, possiamo fare delle richieste che non ritornano un intera pagina, ma ci ritornano indietro dei dati, xml, testo, json, immagini, ecc.. Grazie ad AJAX è possibile caricare porzioni di pagina, via javascript modifichiamo il DOM senza però caricare la pagina. In pratica si modifica una parte del DOM senza ricaricare la pagina. In HTTP il modello è quello della pagina (statica o dinamica) Si può lavorare a livello di porzione di pagina usando JavaScript ma non si può interagire con dati remoti perchè si lavora sul client Sfruttando il DOM di JavaScript e le chiamate AJAX si possono modificare in modo asincrono o sincrono piccole porzioni della pagina corrente senza ricaricarla completamente Viene usato per esempio da Google Maps, Gmail, Youtube,.. <script> function update(id) { var el=document.getElementById(id); el.innerHTML=<chiamata ad una funzione remota di un server> } </script> Ajax: XMLHttpRequest XMLHttpRequest è un oggetto JavaScript messo a disposizione dal browser Permette di eseguire chiamate HTTP tramite JavaScript Nonostante il nome, non si limita ad essere usato con XML ma accetta anche altri formati per esempio JSON Per istanziare questo oggetto sono necessarie istruzioni diverse a seconda del browser, esempio: function getXMLHttpRequestOvject() { var request=null; if (windows.XMLHttpRequest) { request=new XMLHttpRequest(); } else if (windows.ActiveXObject) { //Older IE request = new ActiveXObject("MSXML2.XMLHTTP.3.0"); } return request; } Dopo aver instanziato un oggetto XMLHttpRequest si possono usare i suoi metodi abort() getAllResponseHeaders() getResponseHeader(headername) open(methos,url,async,username,password) send(data) setRequestHeader(headername,value) Chiamata sincrona il browser si ferma in attesa della risposta, mentre asincrona il browser va avanti, tipicamente quando si usa ajax si usa chiamata asincrona. Oltre i metodi l'oggetto ha anche le sue proprietà: onreadystatechange -> permette di definire/richiamare una funzione che viene invocata quando cambia la proprietà readyState readyState -> stato della richiesta responseText -> risposta/pagina in formato testo responseXML -> risposta in XML status -> codice HTTP (200,400,ecc.) statusText -> testo della risposta HTTP (Ok, Not found) Le chiamate possono essere asincrone oppure sincrone, come specificato nel terzo parametro del metodo open() open(method,URL,async) method: GET, POST, HEAD async: FALSE per chiamate sincrone async: TRUE (default) per chiamate asincrone In generale si suggerisce di usare chiamate asincrone send() invia la richiesta Durante una chiamata Ajax si passa attraverso vari stati: 0 UNSENT -> open() has not been called yet 1 OPENED -> send() has not been called yet 2 HEADERS_RECEIVED -> send() has been called, and header and status are available 3 LOADING -> Downloading; reasponseText holds partial data 4 DONE -> the operation is complete La natura asincrona di Ajax permette al browser di accettare input dall'utente e modificare la pagina mentre il codice JavaScript testa il valore della proprietà readyState Ad ogni cambiamento del valore di readyState si può invocare una funzione di callback associata alla proprietà onreadystatechange esempio funzione callback: function ajaxCallback() { let res = document.getElementById(…); if ((xhr.readyState == 4) & (xhr.status == 200)) { // codice 200 OK nella risposta HTTP if (xhr.responseText != null) res.innerHTML = xhr.responseText; else res.innerHTML = “No data received”; } else alert("Ajax error: " + xhr.statusText); } xhr.open(“GET”, url, true); xhr.onreadystatechange = ajaxCallback; xhr.send(); Esempio 1 completo readyState <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ajax exmple</title> <script src="utility.js"></script> <script> var stato = new Array("uninitialized", "loading", "loaded", "interactive", "complete"); var xhr = null; function ajaxcall(url) { xhr = getXMLHttpRequestObject(); xhr.onreadystatechange = function () { // callback let el = document.getElementById("myelem"); el.innerHTML += "<b>readyState: </b> " + xhr.readyState + "....." + stato[xhr.readyState] + "<br>"; if ((xhr.readyState == 4) & (xhr.status == 200)) { el.innerHTML += xhr.responseText; } } xhr.open("GET", url, true); xhr.send(); } </script> </head> <body> <form method="post"> <input type="button" onclick="ajaxcall('1_donothing.php');" value="Click here" /> </form> <div style="margin:50px; padding:10px; background-color:greenyellow;" id="myelem"></div> </div> </body> </html> utility.js /* set XMLHttpRequest for some browsers */ /* look for more complete function */ function getXMLHttpRequestObject() { var ref = null; if (window.XMLHttpRequest) { ref = new XMLHttpRequest(); } else if (window.ActiveXObject) { // Older IE. ref = new ActiveXObject("MSXML2.XMLHTTP.3.0"); } return ref; } Esempio 2 con JSON: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ajax exmple</title> <script src="utility.js"></script> <script> function getdata(url) { xhr = getXMLHttpRequestObject(); xhr.onreadystatechange = function () { if ((xhr.readyState == 4) & (xhr.status == 200)) { jsondoc = JSON.parse(xhr.responseText); print(jsondoc); } } xhr.open('GET', url, true); xhr.send(null); } function print(a) { let el = document.getElementById("mytable"); let out = "<table border='1' cellpadding='5'>"; for (let i = 0; i < a.length; i++) { //elements can be accessed as object properties, with . notation out += "<tr><td>" + a[i].name + "</td>"; //elements can be accessed as associative arrays, with keys out += "<td>" + a[i]["surname"] + "</td>"; out += "<td>" + a[i].year + "</td></tr>"; } out += "</table>"; el.innerHTML = out; } </script> </head> <body> <form> <input type="button" value="GET JSON" onclick="getdata('exampleJSON.php');"> </form> <br/><br/> <center> Table filled with data requested from the server: <br/><br/> <div id="mytable"></div> </center> </body> </html> exampleJSON.php <?php header("Content-Type: application/json"); /* JSON output below shoud be produced dynamically */ ?> [ { "name":"Mario", "surname": "Bianchi", "year":"2001" } ] Nel caso di uso del metodo GET si possono inviare dei parametri costruendo la querystring let quesrystring="?par1="+val1+"&par2="+val2; let url=encodeURI(endpoint+querystring); xhr.open("GET",url,true); xhr.send(); Nota: In alcuni browser c'è un limite massimo sul numero di caratteri che si possono scrivere nelle querystring Nel caso di uso del metodo POST i dati vengono inviati come parametri di send() Si devono anche specificare alcuni header HTTP Esempio: params=encodeURI("par1=" + val1 + "&par2=" + val2); xhr.open("POST", url, true); xhr.setRequestHeader(“Content-type”,”application/x-www-form-urlencoded”); xhr.send(params); DOM: Document Object Model Document: il browser trasforma ogni documento HTML che legge in un oggetto e definisce la variabile globale document per far riferimento a questo oggetto Object: questo oggetto è caratterizzato da proprietà e metodi Model: il browser fornisce un modello del documento letto, questo modello è un albero La radice dell'albero corrisponde all'elemento <html> Seguono i nodi associati agli altri elementi della pagina <head>, <body>, <p>, <h1>, ... Ogni elemento può contenere: test -> text node, attributi -> attribute node, commenti -> comment node, altri elementi Per accedere agli elementi del documento è necessario selezionarli usando i metodi offerti dal DOM: var el1=document.getElementById("id"); var el2=document.getElementsByName("error"); var el3=document.getElementsByTagName("span"); var el4=document.getElementsByClassName("warning"); var el5=document.querySelector(".warning"); esiste anche document.all -> var el6=document.all Un Document può essere visto come un albero di nodi (Node) Il tipo Node definisce proprietà e metodi che permettono attraversare questo albero Ogni nodo ha le seguenti proprietà nodeType (intero da 1 a 12) Document=9 Element=1 Text=3 Comments=8 Ogni nodo ha le seguenti proprietà nodeName -> nome nodo nodeValue -> contenuto nodo parentNode -> nodo padre del nodo corrente childNodes -> lista dei nodi figli firstChild, lastChild, nextSibling, previousSibling Molti elementi HTML hanno degli attributi Il DOM definisce i metodi per accedere/modificare i valori degli attributi object.getAttribute("attribute") si accede all'elemento con uno dei metodi precedenti si ricavano i valori dei suoi attributi var el=document.getElementById("myimg"); console.log(el.getAttribute("alt")); console.log(el.getAttribute("src")); object.setAttribute("attribute","value") si accede all'elemento e si modificano i valori dei suoi attributi La modifica dei valori degli attributi non si vede nel sorgente HTML: agendo sul DOM si modifica il contenuto di una pagina senza ricaricarla Contenuto degli elementi, per esempio <p> La proprietà innerHTML ritorna il contenuto di un elemento come stringa con markup La proprietà innerText ritorna il contenuto di un elemento come stringa di testo E' anche possibile modificare il contenuto di un documento agendo a livello di nodi grazie a metodi quali: createElement() createTextNode() cloneNode() ecc. API FETCH JavaScript è un linguaggio single-threaded, tutte le attività concorrenti vengono messe in coda, una sola opzione alla volta. Vengono introdotte le chiamate asincrone, le callbacks, promises (api fetch) e async/await, tutte le volte che parte una chiamata Ajax, passa attraverso vari stati e solo quando è terminata correttamente arrivano i dati, e mandiamo in esecuzione la callback che visualizza i dati rispetto alla comunicazione. In Ajax abbiamo visto in concetto di callback, una funzione che viene eseguita al termine di una chiamata asincrona La Fetch Api usa le promise, cioè degli oggetti (Response) restituiti dalle chiamate asincrone Le chiamate devono "sapere cosa fare" quando terminano i task asincroni e arrivano le risposte Una promise è un oggetto che produrrà un risultato nel futuro. Il risultato può essere: il valore cercato la ragione per cui tale valore non viene restituito (per esempio se c'è stato un errore a livello di rete) Una promise può trovarsi in uno stato tra: fulfulled, rejected, pending Response.ok -> true/false (true 200-299, false) Response.status -> codice della risposta (200 in caso di successo) Response.statusText -> testo del codice (codice 200 è OK) Response.Body.text() -> legge stream e ritorna promise che contiene stringa Response.Body.json() -> legge stream e ritorna promise che contiene oggetto json Response.Body.blob() -> legge stream e ritorna promise che contiene blob Esempio fetch di un blob: const image=document.querySelector('.my-image'); fetch('flowers.jpg').then(function(response) { return response.blob(); }).then(function(blob) { const objectURL = URL.createObjectURL(blob); image.src=objectURL; }); Si possono anche mandare dati in post fetch(url, { method: "post", headers: {"Content-type":"application/x-www-form-urlencoded" }, body: "email="+usermail, }).then(function(response) { /* code for response */ return response.text().then(function (result) { /* code fore result */ }); }); } Cookies E' possibile leggere/scrivere i cookies della pagina correntemente visualizzata nel browser usando la proprietà document.cookie, questa proprietà può contenere solo stringhe allCookies=document.cookie; //leggere cookie document.cookie=newCookie; //possibile sovrascrivere I cookie sono scambiati tra client e server ad ogni richiesta di uno specifico dominio, vale per le pagine, per richieste ajax, per immagini e servono per tenere traccia dell'utente. Web Storage Permette di memorizzare dati sul browser dell'utente in modo: permanente: localStorage -> simile cookies persistenti temporaneo: sessionStorage -> simile cookies sessione Web storage fornisce maggiori capacità di memoria rispetto ai 4 KB dei cookies Memorizza dati in forma di coppie key=value localStorage.setItem("client1","Rossi"); -> oppure localStorage.client1="Rossi"; localStorage.getItem("client1"); -> oppure var c=localStorage.client1; localStorage.removeItem("client1"); -> cancellare la chiave localStorage.clear() -> rimuove tutto L'oggetto sessionStorage è uguale all'oggetto localStorage, ma memorizza i dati solo per la durata della sessione I dati vengono quindi persi quando si chiude browser/tab jQuery jQuery è una libreria JavaScript, semplifica lo scripting client-side, è free e open-source, è rilasciata sotto licenza MIT e GPL v.2, viene usata da molto colossi come Google, Dell, Wordpress ecc. Download della versione corrente della libreria Include prendendo l'indirizzo di una CDN che distribuisce jQuery <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/.../jquery.min.js"> </script> </head> La sintassi di jQuery permette di selezionare elementi HTML e di eseguire azioni su di essi $(selector).action() $ per definire/accedere a jQuery (selector) per selezionare gli elementi HTML action() per specificare l'azione da svolgere Come nel caso di JavaScript "standard", anche con jQuery si può agire solo su elementi HTML già caricati nella pagina corrente JavaScript: document.getElementById("demo").innerHTML="Hello World!"; jQuery: $("#demo").html("Hello World!"); jQuery Selettori $("*") -> tutti gli elementi $(this) -> elemento HTML corrente $("p.intro") -> <p> con class="intro" $("p:first") -> <p> primo elemento $("ul li:first") -> <li> primo elemento di <ul> $("ul li:first-child") -> <li> primo elemento di tutti gli <ul> in jQuery, la maggior parte degli eventi del DOM hanno un metodo jQuery equivalente: Events Mouse -> keybords -> Form -> Document/Window click -> keypress -> submit -> load dbclick -> keydown -> change -> resize mouseenter -> keyup -> focus -> scroll mouseleave -> blur -> unload Spesso i metodi jQuery sono all'interno dell'evento ready per evitare al codice jQuery di essere eseguito prima del caricamento del documento $(document).ready(function() { //metodi jQuery qui... }); La funzione $.ajax() permette di fare chiamate HTTP asincrone $.ajax(url, [, options] ) $.ajax([options]) url -> indirizzo della chiamata success -> funzione da invocare se richiesta ok error -> funzione da invocare se fallisce richiesta type -> GET o POST data -> dati da inviare come parametro della richiesta async -> true (default) o false $(selector.load(URL,data,callback); $(selector.post(URL,data,callback,dataType); $(selector.get(URL,data,callback,dataType); jQuery Tables
  8. C# Sharp e gli iteratori, sono una maniera di rappresentare una sequenza di elementi che hanno in comune il tipo, una catena, una stringa, una sequenza di cosi, che hanno tutti in comune il tipo T. Partiamo da come dovrebbe essere: IEnumerable<T> - IEnumerator<T> GetEnumerator() IEnumerator<T> - bool MoveNext() - T current { get; } - void Dispose() Nota: in Java le classi Iterable e Iterator svolgono lo stesso ruolo Modelliamo gli intervalli (chiusi) di interi in modo tale che siano "foreach-abili", per semplicità, ignoriamo Equals (& company) Per esempio: var ontToFive = new IntInterval(1,5); foreach (var i in oneToFive) Console.WriteLine(i); Classe IntInterval public class IntInterval : IEnumerable<int> { public int LowerBound { get; private set; } public int UpperBound { get; private set; } public IntInterval(int lowerBound, int upperBound) { this.LowerBound = lowerBound; this.UpperBound = upperBound; } public IEnumerator<int> GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } private class Enumerator : IEnumerator<int> { ... } } Classe IntInterval.Enumerator private class Enumerator : IEnumerator<int> { private readonly IntInterval _interval; private int _current; public Enumerator(IntInterval interval) { this._interval = interval; this.Reset(); } public void Reset() { this._current = this._interval.LowerBound – 1; } public bool MoveNext() { return ++this._current <= this._interval.UpperBound; } public int Current { get { return this._current; } } object IEnumerator.Current { get { return this.Current; } } public void Dispose() { } } Enumerator La classe IntInterval.Enumerator è piuttosto semplice da scrivere, ma non particolarmente interessante Da C# 2, il compilatore crea in automatico degli Enumerator a partire da un blocco di codice che restituisce un valore dopo l'altro usando yield return public class IntInterval : IEnumerable<int> { public int LowerBound { get; private set; } public int UpperBound { get; private set; } public IntInterval(int lowerBound, int upperBound) { this.LowerBound = lowerBound; this.UpperBound = upperBound; } public IEnumerator<int> GetEnumerator() { for (var a = this.LowerBound; a <= this.UpperBound; ++a) yield return a; } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } Iteratori Un blocco, corpo di un membro il cui tipo di ritorno sia IEnumerator/IEnumerator<T> o IEnumerable/IEnumerable<T>, che contiene yield return è in iteratation-block Tale membro viene chiamato iterator(iterator) - non può contenere return o avere parametri passati per riferimento (ref o out) - può contenere yield break, che termina la sequenza L'invocazione di un iteratore non provoca l'immediata esecuzione del codice, ma la costruzione di un oggetto enumerator (o enumerable) per la sequenza corrispondente
  9. Metadati & Reflection Annotazioni per assembly, tipi, membri e parametri - In Java @Blabla - Un pò tipo i modificatori public, private,.. - Ma definite dall'utente . sono classi che estendono System.Attribute . per esempio, Serializable (System.SerializableAttribute) su una classe indica che i suoi oggetti sono serializzabili public class TapAttribute : Attribute { } [Tap] //classe annotata con Tap public class Program { [Tap] public static void Main(string[] args) { } } Dependency Injection Un esempio di classe per spedire email: public class EmailSender { public bool SendEmail(string to, string body) { if (to==null) throw new ArgumentNullException(nameof(to)); if (body==null) throw new ArgumentNullException(nameof(body)); //...send mail and return true return false; } } Questa classe e i suoi tipi ausiliari sono un esempio di componente (una volta "impacchettate" in una DLL) BulkEmailSender public class BulkEmailSender { private readonly EmailSender _emailSender; private readonly string _footer; public BulkEmailSender(string footer) { this._emailSender = new EmailSender(); this._footer = footer; } public void SendEmail(List<string> addresses, string body) { if (addresses == null) throw new ArgumentNullException(nameof(addresses)); if (body == null) throw new ArgumentNullException(nameof(body)); foreach (var a in addresses) { if (!this._emailSender.SendEmail(a, body + this._footer)) throw new Exception("Cannot send email"); } } } Esistono vari tipi di DI, consideriamo constructor injection (è quella da usare di default) che inietta tramite i costruttori - Altre sono la method, property, field,.. L'idea è estremamente semplice: i costruttori richiedono gli oggetti che servono direttamente, invece di crearli in codice (senza factory) public BulkEmailSender(string footer) { this._emailSender = new EmailSender(); this._footer = footer; } public BulkEmailSender(IEmailSender emailSender, string footer) { this._emailSender = emailSender; this._footer = footer; } in codice (con factory) public BulkEmailSender(string footer) { this._emailSender = new EmailSender(); this._footer = footer; } public BulkEmailSender(IEmailSenderFactory factory, string footer) { this._emailSender = factory.CreateNew(); this._footer = footer; } Dove: interface IEmailSender { bool SendEmail(string to, string body); } interface IEmailSenderFactory { IEmailSender CreateNew(); } // e, per esempio, una factory è: class EmailSenderFactory : IEmailSenderFactory { public IEmailSender CreateNew() { return new EmailSender(); } } Altro esempio di (non static) Factory public class C { private readonly IPointFactory _pointFactory; private readonly ILineFactory _lineFactory; public C(IPointFactory pointFactory, ILineFactory lineFactory) { this._pointFactory = pointFactory; this._lineFactory = lineFactory; } public void DoSomething(/* ... */) { // ... ILine newLine = CreateLine(/* ... */); // ... } private ILine CreateLine(int x0, int y0, int x1, int y1) { IPoint p0 = this._pointFactory.Create(x0, y0); IPoint p1 = this._pointFactory.Create(x1, y1); return this._lineFactory.Create(p0, p1); } } Diventa facile sostituire un'implementazione con un'altra Di conseguenza, diventa più facile il testing ed estendere le funzionalità, per esempio, Decorator Esempio di Decorator class LoggingEmailSender : IEmailSender { private readonly IEmailSender _originalSender; public LoggingEmailSender(IEmailSender originalSender) { if (originalSender == null) throw new ArgumentNullException(nameof(originalSender); this._originalSender = originalSender; } public bool SendEmail(string to, string body) { Console.WriteLine("Sending mail to {0}", to); return this._originalSender.SendEmail(to, body); } } Principio di minima conoscenza public void Purchase(Customer c) { Money m=c.GetWallet().GetMoney(); this.RecordSale(..., m); } // Nel testing: Money m = new Money(5); Wallet w = new Wallet(m); Customer c = new Customer(w); Goods g = g.Purchase(c); //assert Versione tradizionale con singleton DB.Init("..."); //inizializza il singleton Logger.Init(); //idem, l'ordine è importante! var bulk=new BulkEmailSender(); //apparentemente indipendente da sopra //ma se il Logger non è stato inizializzato //EmailSender (istanziato da BulkEmailSender) //si shchianta con la DI vard db=new DB(...); var logger=new Logger(db); var emailSender=new EmailSender(logger); var bulk=new BulkEmailSender(emailSender, ""); sbagliando l'ordine la compilazione fallisce! DI container Siccome le dipendenze sono esplicite, la composizione degli oggetti spesso si può automatizzare, è quello che fanno i container DI Si programmano associando implementazioni a interfacce: - via codice, max flessibilità e controllo statico sui tipi, ma la riconfigurazione richiede ricompilazione - via file di configurazione (tipicamente XML) E poi loro gestiscono la creazione e lo scope (singleton, factory o container) Non è necessario usare un DI container per usare la DI Come per esempio non è necessario usare una libreria di logging per "loggare" Le implementazioni non mancano: Ninject, Autofac, Guice, NanoContainer, Spring.NET, Unity,.. Inversion of Control e Dependency Injection sono la stessa cosa? IoC è un concetto più generale - Ogni framework usa IoC (quando associate un'azione a un pulsante in una GUI lo state usando) DI è il nome più corretto Ninject Un framework per le dependency injection open source per .NET E una maniera di disaccoppiare le classi e rendere più facili il riuso del codice, cambiando le implementazioni dell'interfaccia, rendere il codice più testabile e mantenere il codice DI Container Una libreria che automatizza molti dei task per creare e comporre degli oggetti. Ninject è un framework open source, i vantaggi sono tanti, è ancora in sviluppo, è veloce e non pesa molto, potente fornisce tutte le funzionalità ed è facile da utilizzare Official site: http://www.ninject.org Disponibile anche tramite NuGet Vediamo l'esempio citato sopra public interface IEmailSender { bool SendEmail(string to, string body); } public class AnEmailSender : IEmailSender { /∗ ... ∗/ } public class BulkEmailSender { private readonly IEmailSender emailSender; private readonly string footer; public BulkEmailSender(IEmailSender emailSender /∗, string footer∗/) { this. emailSender = emailSender; this. footer = String.Empty; } public void SendEmail(List<string> addresses, string body) { /∗ ... ∗/ } } Come faccio a usare Ninject? Costruisco il kernel, un oggetto centrale Ikernel kernel=new StandardKernel(); dico al nucleo quali sono le classi che mi interessano kernel.Bind<IEmailSender>().To<AnEmailSender>(); richiedo un istanza del servizio var bulkES=kernel.Get<BulkEmailSender>(); usiamo il servizio bulkES.SEndEmail(new List<string> {"[email protected]", "[email protected]"}, "hi"); La capacità di associare il tipo del servizio (interfacce o classe astratte) al tipo di implementazione del mio servizio Tipato fortemente o debolmente kernel.Bind<IEmailSender>().To<AnEmailSender>(); // ok kernel.Bind<IEmailSender>().To<string>(); // compilation error kernel.Bind(typeof(IEmailSender)).To(typeof(AnEmailSender)); // ok kernel.Bind(typeof(IEmailSender)).To(typeof(string)); // ”ok” Le classi sono per default legate a se stesse kernel.Bind<BulkEmailSender>().To<BulkEmailSender>(); kernel.Bind<BulkEmailSender>().ToSelf(); Injection Patterns Ninject supporta due forme i injection: Constructor Injection Inizialization methods Costruire l'oggetto, qual è l'ambito in cui l'oggetto deve essere ancora vivo, e si usano i metodi che finoscono con scope. Transient -> .InTransientScope() -> una nuova istanza ogni volta (equivalente di new) Singleton -> .InSingletonScope() -> all'interno esiste una sola istanza (creato l'oggetto e viene richiesto sempre e solo questo) Thread -> .InThreadScope() -> una istanza per thread Request -> .InRequestScope() -> una istanza per la durata del web request Custom -> .InScope() -> definire una funzione e quale oggetto venga restituito a seconda del contesto in esecuzione kernel.Bind<IEmailSender>().To<AnEmailSender>().InTransientScope(); kernel.Bind<BulkEmailSender>().ToSelf().InSingleTonScope(); var b1=kernel.Get<BulkEmailSender(); var b2=kernel.Get<BulkEmailSender>(); Debug.Assert(ReferenceEquals(b1,b2)); var e1=kernel.Get<IEmailSender>(); var e2=kernel.Get<IEmailSender>(); Debug.Assert(!RefernceEquals(e1.e2)); Torniamo al nostro esempio: public interface IEmailSender { bool SendEmail(string to, string body); } public class BulkEmailSender { private readonly IEmailSender _emailSender; private readonly string _footer; public BulkEmailSender (IEmailSender emailSender, string footer) { this._emailSender=emailSender; this._footer=footer; } public void SendEmail(List<string> addresses, string body) { /*...*/ } } public class AnEmailSender : IEmailSender { /*...*/ } Ora, kernel.Get<BulkEmailSender>() non funziona più - Passare argomenti alla Get<>() kernel.Get<BulkEmailSender>(new ConstructorArgument("footer","Bye"); - aggiustare l'argomento //usando WithConstructorArgument kernel.Bind<BulkEmailSender>().ToSelf().WithConstructorArgument("footer","my Footer"); //delegate crendo nuova istanza kernel.Bind<BulkEmailSender>().ToMethod(context => new BulkEmaailSender(context.kernel.Get<IEmailSender>(),"my footer")); Refactory esempio: public interface IEmailSenderFactory : IEmailSenderFactory public IEmailSender Creat() { return new AnEmailSender(); } } public class IBulkEmailSenderFactory { IBulkEmailSender Create(string footer); } implementazioni: public class EmailSenderFactory : IEmailSenderFactory { public IEmailSender Create() { return new AnEmailSender(); } } public class BulkEmailSenderFactory : IBulkEmailSenderFactory { private readonly IEmailSenderFactory emailSenderFactory; public BulkEmailSenderFactory(IEmailSenderFactory emailSenderFactory) { this. emailSenderFactory = emailSenderFactory; } public IBulkEmailSender Create(string footer) { return new BulkEmailSender(this. emailSenderFactory.Create(), footer); } } collego il kernel IKernel kernel = new StandardKernel(); kernel.Bind<IEmailSender>().To<AnEmailSender>(); kernel.Bind<IEmailSenderFactory>().To<EmailSenderFactory>().InSingletonScope(); kernel.Bind<IBulkEmailSenderFactory>().To<BulkEmailSenderFactory>().InSingletonScope(); // ... var factory = kernel.Get<IBulkEmailSenderFactory>(); var bulkEmailSender = factory.Create("Bye"); Multi Injection public interface IWeapon { string Hit(string target); } public class Sword : IWeapon { public string Hit(string target) { return "Slice " + target + " in half"; } } public class Dagger : IWeapon { public string Hit(string target) { return "Stab " + target + " to death"; } } //... static void Main(string[] args) { IKernel kernel = new StandardKernel(); kernel.Bind<IWeapon>().To<Sword>(); kernel.Bind<IWeapon>().To<Dagger>(); var weapon = kernel.Get<IWeapon>(); // error: which one? IEnumerable<IWeapon> weapons = kernel.GetAll<IWeapon>(); foreach (var w in weapons) Console.WriteLine(w.Hit(”bad guy”)); Se la classe Samurai riceve un IWeapon[], List<IWeapon> o IEnumerable<IWeapon> public class Samurai { private readonly IEnumerable<IWeapon> allWeapons; public Samurai(IWeapon[] allWeapons) { this. allWeapons = allWeapons; } public void Attack(string target) { foreach (var weapon in this. allWeapons) Console.WriteLine(weapon.Hit(target)); } dopo dobbiamo fare: kernel.Get<Samurai>().Attack("your enemy");
  10. var Solo per dichiarare variabili locali, il tipo (inferito) è quello dell'inizializzatore Esempio: int i=0; var i=0; //equivalenti, finchè non cambia inizializz. E' chiaramente molto comoda con i generici... List<List<string>> lls = new List<List<string>>(); var lls=new List<List<string>>(); Non solo per i pigri, essenziale in alcuni casi Proprietà (Properties) Metodi get/set che invocati attraverso la sintassi di accesso a campo, per esempio, exp.P = 3 usate per caching, lazy loading, ecc.. è possibile specificare solo il getter o il setter Per il setter, value indica il valore "scritto" Al client "sembrano" accessi a campo: è ragionevole usarle solo se getter/setter efficienti In quanto metodi, possono essere virtual, abstract, comparire nelle interfacce Uno dei due può avere un modificatore di accesso più restrittivo (per es. il setter private) Uso ovvio con getter e setter public class C { private int_i; public int I { get { return this._i; } set { this._i=value; } } } Vediamo come richiamare la classe e le sue proprietà; C aC = new C(); aC.I = 41; ++aC.I // !!! Console.WriteLine(aC.I); //stampa 42 Auto-Properties Come una property, ma il campo nascosto è generato automaticamente dal compilatore - non se ne conosce il nome publi class C { public int I { get; set; } public int K { get; } public int Z { get; private set; } } Con ReSharper la trasformazione fra una versione e l'altra richiede solo un ALT Return... Le Auto-Properties si possono inizializzare: - sinstassi analoga ai campi public int I { get; set; } = 37; - come per i campi . inizializzazioni eseguite nell'ordine in cui sono scritte. . nell'espressione di inizializzazione non si può fare riferimento al this. Properties senza campo - Esempio: public class Person { public int YearOfBirth { get; set; } public int Age { get { return DateTime.Now.Year - this.YearOfBirth; } } } // ... var p=new Person { YearOfBirth=1973}; Console.WriteLine(p.Age); Scorciatoie varie Maniera compatta per dichiarare un Array se conosciamo i valori, sparito il tipo string in var, sparita la dimensione che lo deduce da solo. var array = new[] {"ciao", "mondo" }; Costruire un oggetto ed assegnare ai campi qualche valore var anA = new A(3) { G=3 }; var anotherA = new A { F=5, G=3 }; Qui costruisco una nuova lista ma subito inserisco 3 elementi var ls = new List<string>() {"qui", "quo", "qua" }; Ora vediamo il dizionario con chiave e valore var d = new Dictionary <int, string> () { {1, "pippo"}, {2, "pluto"} }; // oppure: var d1 = new Dictionary<int, string> () { {[1]="pippo"}, {[2]="pluto" } }; Operator overloading In molti linguaggi alcuni operatori sono overloaded (per es. quelli aritmetici) C# permette di definire il comportamento di molti operatori, quando (almeno) un operando è di un tipo definito dall'utente - Non si possono aggiungere operatori o variarne la precedenza - Non si può ridefinire l'assegnazione (nemmeno struct) Gli operatori vanno definiti public static e hanno come nome operator op - Per chi conosce C++: "this" non è l'operando sinistro, negli operatori binari servono due parametri Esempio di uso dell'overloading DateTime x = DateTime.Now; DateTime y = new DateTime(1982,1,1); TimeSpan t = x - y; DateTime k = x + t; DateTime TimeSpan sono due tipi (struct) di sistema Operator overloading esempio: public class C { public static C operator +(C x, int y) { return null; } } public class Program { public static void Main(string[] args) { var c = new C(); C foo = c+3; c+=27; // come scrivere c=c+27; } } Alcuni operatori (== e != e <,>= e <=) vanno a coppie, se si definisce uno , si deve definire anche l'altro Se si definisce == è buona norma ridefinire anche Equals e GetHashCode class C { private int x, y; public override bool Equals(Object obj) { if (obj == null) return false; if (obj.GetType()==typeof(C)) { C other = (C) obj; return this.x == other.x && this.y == other.y; } return false; } public override int GetHashCode() { return... } } User-defined conversions Il tipo sorgente o destinazione deve corrispondere al tipo che contiene la conversione public class C { public static implicit operator C(int i) { return null; } public static implicit operator int(C from) { return 1; } public static explicit operator string(C from) { return "a"; } } // ... C c=42; int i=c; string s=(string)c; Indexer Misto fra proprietà e overloading di [] (una classe può dichiarare diversi indexer, in overload) var h=new Dictionary<string, int>(); h["ciao"]=7; public class C { private int _x public int this[double a, double b] { get {return 42;} set {this._x=value;} } } //... var c=new C(); c[4,2.0]=7; int i = c[Math.PI,0]; // Si possono usare per inizializzare var conversion = new Dictionary<string, int> { ["diciotto"]=18, ["diciannove"]=19, ... Dynamic In C# 4 è arrivato il tipo dynamic che corrisponde al tipo <<staticamente dinamico>> (=un tipo che richiede binding dinamico) - Molto elegante, ma dietro le quinte diventa Object e viene usata la reflection a palate (=lento, come usare un linguaggio dinamicamente tipato) . è un uso furbo/ottimizzato della reflection, si vedano gli expression tree e il DLR - Comodo per certi scopi, per es. interfacciarsi a linguaggi dinamicamente tipati Dynamic è totalmente diverso da var Delegate Tipi assimilabili ai tipi funzionali di Caml - un delegate permette di invocare uno o più metodi conoscendone solo tipo di ritorno e tipo dei parametri La dichiarazione di un tipo delegate D, per es. public delegate int D(int a, int b); // int x int -> int definisce una classe che estende System.Delegate - essendo classsi, l'equivalenza di tipi delegate è per nome: public delegate int Foo(int a, int b); definisce un tipo delegate diverso (incompatibile) da D anche se entrambi descrivono un metodo che, presi due interi, restituisce un intero. Se D è un tipo delegate, un oggetto di tipo D si ottiene tramite new, passando come argomento il nome di un metodo; per esempio: new D(nomeMetodo); - Nota: nomeMetodo potrebbe individuare più di un metodo per via dell'overloading, in quel caso viene scelto il più specifico Se pippo è un oggetto di tipo delegate, per invocare i metodi associati a pippo si usa la sintassi classica dell'invocazione: pippo(...); public class Program { public delegate int D(int a, int b); public delegate int Foo(int a, int b); private static int Sum(int x, int y) { return x + y; } private int Max(int i, int j) { return Math.Max(i, j); } public static void Main(string[] args) { D d1 = new D(Program.Sum); Foo f1 = new Foo(Sum); // Sum = Program.Sum Console.WriteLine(d1(1, 2)); Console.WriteLine(f1(1, 2)); D d2 = new D(new Program().Max); Foo f2 = new Foo(new Program().Max); Console.WriteLine(d2(1, 2)); Console.WriteLine(f2(1, 2)); // D d3 = f1; // errore! } } Grazie alle conversioni implicite.. public class Program { public delegate int D(int a, int b); public delegate int Foo(int a, int b); private static int Sum(int x, int y) { return x + y; } private int Max(int i, int j) { return Math.Max(i, j); } public static void Main(string[] args) { D d1 = Program.Sum; Foo f1 = Sum; // Sum = Program.Sum Console.WriteLine(d1(1, 2)); Console.WriteLine(f1(1, 2)); D d2 = new Program().Max; Foo f2 = new Program().Max; Console.WriteLine(d2(1, 2)); Console.WriteLine(f2(1, 2)); // D d3 = f1; // errore! } } Invocation-List Ogni (oggetto) delegate ha una invocation-list associata - Quando creiamo un delegate, l'unico elemento della lista è il metodo che abbiamo passato alla new Invocando un (oggetto) delegate, invochiamo in sequenza i metodi della sua invocation-list Operazioni sull'invocation-List Ogni tipo delegate D implicitamente definisce D operator +(D x, D y) D operator -(D x, D y) bool operator==(System.Delegate x, System.Delegate y) bool operator!=(System.Delegate x, System.Delegate y) Quindi i delegate possono essere - combinati con + e += (il delegate risultante corrisponde all'invocazione di tutti i metodi di x, seguiti da quelli di y) - rimossi con - e -= - confrontati per vedere se puntano la stessa lista di metodi Delegate generici Visto che sono classi, anche i delegate possono essere generici. Per esempio delegate int Comparer<T>(T x, T y); In .NET 3.x sono stati introdotti: - Azioni, metodi void che si aspettano T1...Tn: Action, Action<T>, Action<T1,T2>,... - Funzioni da T1...Tn in TResult: Func<TResult>, Func<T,TResult>, Func<T1,T2,TResult>,... - Predicati: Predicate<T> private static int Sum(int x, int y) { ... } private static int Max(int i, int j) { ... } public static void Main(string[] args) { Func<int, int, int> f = Sum; Func<int, int, int> g = Max; Console.WriteLine( (f+g)(1, 2) ); // 2 var k = g + f; Console.WriteLine( k(1, 2) ); // 3 Console.ReadLine(); } Metodi anonimi Permettono di creare dei delegate a partire da un frammento di codice, esempio: Func<int, int, int> f = delegate(int a, int b) { return a+b}; Non possiamo usare var per dichiarare f Sono chiusure (closure): possono accedere a variabili locali del metodo che li contiene Lambda Expressions (Closures) Assimilabili a lambda-astrazioni del lambda-calcolo, ovvero definizioni di funzioni "inline" Esempi: (int x, int y) => x + y; //somma x e y a = a * a; //funzione quadrato (x,y) => {if (x<y) return x; else return y;} //restituisce il minimo Il tipo dei parametri può essere inferito, se il parametro è solo uno non servono le parentesi Le lambda NON sono delegate, ma sono convertibili in delegate public static void Foo(Action<int> bar) { bar(21); } public static void Main(string[] args) { int k = 0; Action<int> f = delegate(int a) { k += a; }; Action<int> g = a => k += a; Foo(f); Foo(g); Console.WriteLine(k); // 42 Console.ReadLine(); } Lambda-like syntax Sintassi molto simile alle lambda per - dichiarazione di proprietà public int Z {get {return I+K;}} public int Z => I+K; - dichiarazione di metodi public int Pippo(int x) {return Z+x;} public int Pippo(int x) => Z+x; EVENTI: Pattern Observer AKA: Dependents, Publish-Subscribe, Listener Motivazione: partizionando un sistema in una collezione di oggetti che cooperano nasce la necessità di mantenere la consistenza Ma senza ridurre la riusabilità delle classi Intento: definire una relazione 1 a molti fra oggetti, in modo che quando uno cambia stato, tutti quelli dipendenti vengano notificati Eventi in .NET Spesso è utile associare delle azioni all'accadere di un certo evento Per esempio il click su un pulsante, la pressione di un tasto, la ricezione di un messaggio dalla rete, ecc.. Gli eventi in .NET portano a livello di linguaggio il pattern Observer - Permettono di disaccoppiare la sorgente dell'evento dalle azioni di risposta - Solo la classe che espone l'evento può sollevarlo, gli altri possono solo registrarsi per ricevere le notifiche Dichiarazione e uso Una classe può esporre degli eventi, dichiarati con: event TipoDelegate NomeEvento; Chi è interessato a un evento può usare:: - l'operatore += per iscrivere un delegate, chiamato in questo caso, event-handler - l'operatore -= per de-iscrivere un event-handler L'vento può essere sollevato (fired) solo all'interno della stessa classe con: nomeEvento(...); tutti gli event-handler iscritti vengono invocati Per sollevare un evento, dobbiamo controllare che non sia null if (this.nomeEvento!=null) this.nomeEvento(/*...*/); non è thread-safe Possibilità 1: var ev=Volatile.Read(ref this.nomeEvento); if (ev!=null) ev(/*...*/); Possibilità 2: this.nomeEvento?(/*...*/); non si può. Si usa this.nomeEvento?.Invoke(/*...*/); Per certi versi, gli eventi stanno ai delegate come le proprietà stanno ai campi public event TipoDelegate NomeEvento; equivale ad avere un campo privato di tipo TipoDelegate e chiamato NomeEvento e due metodi pubblici add e remove delegate void EventHandler (object sender, BlablaEventArgs e); sender indica la sorgente dell'evento (es. button) e contiene le informazioni aggiuntive e BlablaEventArgs è un sottotipo di EventArgs (es. KeyPressEventArgs) public delegate void EventHandler<TEventArgs>( Object sender, TEventArgs e) //Per esempio public class Stock { //... public event EventHandler<PriceChangedEventArgs> PriceChanged; }
  11. Il C# (si pronuncia see sharp) è un linguaggio di programmazione orientato agli oggetti sviluppato da Microsoft all'interno dell'iniziativa .NET, e successivamente approvato come standard dalla ECMA (ECMA-334) e ISO (norma ISO/IEC 23270). La sintassi e struttura del C# prendono spunto da vari linguaggi nati precedentemente, in particolare Delphi, C++, Java e Visual Basic. In questa guida vediamo la versione 7.2 di C#. .Object-Oriented, sintassi alla C (graffe, int, for, ...) .Distinzione fra tipi valore e reference - boxing e unboxing - le stringe sono oggetti immutabili .Ereditarietà singola per classi, ma multipla per le interfacce. Supporta i generici (metodi, classi, e interfacce) .Costruttori per inizializzare gli oggetti .Oggetti creati con new, garbage collected .Gestione degli errori tramite meccanismo di eccezioni .Compilato per un'unica architettura (virtuale) Statement .if, while, do while, for, {}, expression-stmt (espresesione seguita da ";"), dichiarazioni di tipo sono (quasi) uguali. .foreach(T v in exp) che in Java è for(T v : exp) .goto (permesso in certi casi), sostanzialmente sostituisce break/continue etichettati .synchronized è diventato lock .Lo switch - non supporta il "fall-through" se il case non è completamente vuoto - i case possono essere string literal (ora anche in Java 7) - (supporta anche i pattern matching nei case) Java C# (in realtà: .NET) java.lang.Object: System.Object: -toString -ToString -equals -Equals -hashCode -GetHashCode -(finalize) -(finalize) -(altri metodi coi thread) java.lank è un package System è un namespace (java -> classe di java.lang) -che si importano -si dichiarano con namespace e si usano con using Vediamo il primo codice Ciao Mondo: namespace ConsoleApplication { using System; public class Program { public static void Main(string[] args) { Console.WriteLine("ciao mondo"); Console.ReadLine(); } }} si può usare il comando using static System.Console; Permette di usare le classi dichiarate in System senza qualificarle pienamente Console invece di System.Console; Meccanismo analogo per le classi permette di accedere ai membri statici senza esplicitare il nome della classe WriteLine invece di Console.WriteLine Modificatori di Accesso Le classi possono avere questi modificatori di accesso vediamo il confronto con Java: Java c# .public .public .protected .protected - classe e sottoclassi .(friendly) .--- .--- .internal - stesso assembly (dll o exe) .--- .internal protected - protected o internal .--- .private protected - protected e internal (sic) .private .private public: accessibile a tutti private: accessibile solo alla classe Ereditarietà Vediamo prima come si fa in Java prima: Java .class C1 extends C2 implements l1, l2, l3 { C1() super(...) ... C1 (int x) { this(...) ... interface l extends l1, l2, l3, .. In Java le interfacce possono avere campi costanti (final static) ora vediamo l'ereditarietà in C#: c# class C1 : C2, I1, I2, I3 { C1 : BASE (...) { ... C1 (int x) : this (...) { .. interface I : I1, I2, I3 ... In C# le interfacce contengono solo metodi (astratti e pubblici, come in Java) Per convenzione, iniziano tutte con I : IPippo, IPluto, ecc.. Metodi virtuali o no? JAVA: . default: dispatch dinamico . override senza modificatori (ma introdotta @Override) . final rende il dispatch statico, ma evita anche ogni ri-definizione nelle sottoclassi Binding: associazione di un nome a un'operazione (usando, per esempio, i tipi degli operandi/argomenti) in Java sempre statico in C# Dynamic binding -> dynamic dispatch (non viceversa!) Dynamic dispatch: selezione di una particolare implementazione per operazione polimorfa C#: . default: dispatch statico . per avere dispatch dinamico: virtual . quando il metodo esiste già, richiesto override o new (che è default, ma con warning) . una ridefinizione di metodo può essere marcata con sealed per evitare altre ridefinizioni . classe sealed è come final in Java Metodi implementati Se I1 e I2 hanno un metodo m, e C le implementa entrambe, posso implementare diversamente I1.m e I2.m? In Java No, è richiesto un metodo pubblico chiamato m e ce ne può essere solo uno In C# si, grazie all'implementazione esplicita di interfacce public class C : I { int I.Met() { return 1; } } Non ci va nessun modificatore e il metodo risulta inaccessibile attraverso il tipo C. Metodi locali I metodi locali sono sempre privati, dentro a Met stesso, come convenzione di stile si mettono in fondo Non sono visibili agli altri metodi e chi deve capire la classe sa che non ha bisogno di leggerli se non vuole entrare nei dettagli di Met Runtime Type Identification/Cast in Java abbiamo; exp instanceof T (T)exp Object t = exp; t instanceof T ? (T)exp : (T)null in C# abbiamo: exp is T (T)exp exp as T Costanti Java .Campi final static C# .Modificatore readonly analogo a final .Modificatore const, usabile con tipi numerici ed enumerazioni, indica una costante a tempo di compilazione Eccezioni Entrambi hanno try/catch/finally e una gerarchia di eccezioni con radice (java.lang/System).Exception e membri analoghi StackTrace/InnerException Ma C# non ha le eccezioni controllate, quindi non ha la clausola throws nelle intestazioni dei metodi (e non vi costringe a dichiarare/catturare) Le eccezioni si catturano per gestirle catch (Exception e) {Console.WriteLine(e.Message);} eventualmente si risollevano Catch (Exception e) {throw new Exception (e.Message); } magari cambiando tipo catch (Exception e) {throw new MyException(e.Message);} Ok solo per console applications Altrimenti: catch (Exception e) { Debug.WriteLine(e.Message); } cosi si conserva history Oppure usando gli exception filter: private static bool NotifyAndContinue(Exception e){ /*do logging/console writing*/ return false; } ... catch (Exception e) when (NotifyAndContinue(e)) { } volendo cambiare tipo catch (Exception e) {throw new MyEception(e);} Tipi primitivi/valore Java: boolean, char, int, long, float, double, ... C#: bool, char, int, long, float, double, (unsigned) uint, ulong, ... ma int è un alias di Int32, ulong di UInt64, ecc... - object è un alias di Object - string è un alias di String Tipi in .NET I linguaggi supportati dal .NET framework quali C# e VB si dice che sono strongly-typed, ossia fortemente tipizzati, in parole povere ogni variabile od oggetto dichiarato all'interno del programma deve definire un tipo e lo deve rispettare (pena un errore di compilazione). Valore - Le variabili memorizzano direttamente gli oggetti, non è possibile aliasing Questi tipi rappresentano la stragrande maggioranza dei Tipi Primitivi (dati a sè stanti e non complessi, come un numero o un carattere), come System.Int16, System.Char, System.Boolean, System.DateTime. il valore del dato il quale viene allocato nella zona di memoria detta stack Reference - Le variabili memorizzano dei riferimenti a oggetti, l'assegnazione crea degli alias Questi tipi rappresentano tutti quei dati espressi tramite la dichiarazione di classi per descrivere oggetti complessi, essi vengono allocati nella memoria managed heap e non contengono direttamente il valore del dato, ma un puntatore ad una locazione di memoria dove è contenuto il valore vero e proprio, infine come è facile presumere questi possono assumere valore null. C#: struct, tipi di valore In c# è possibile creare i propri tipi valore usando struct I tipi valore possono essere allocati sullo stack, no aliasing Enum Simili a quelli di C/C++, un modo per definire delle costanti di tipo integrale internal enum Color { Red, Green, Blue, } Color c=Color.green; Rilascio automatico delle risorse: using (var pippo=new StreamReader(@"c:\bla")) { //usa pippo... } Generici Simili a quelli Java (ma molto efficienti) Si possono mettere dei vincoli sugli argomenti tramite la clausola where public class C<T> where T : new() { public T Foo() { return new T(); } } Generici, vincoli new(): l'argomento deve essere un tipo instanziabile, col costruttore di default Atype: l'argomento deve essere sottotipo di AType, può essere il nome di un tipo del sistema o di un altro parametro del generico struct: l'argomento deve essere un value type class: l'argomento deve essere un tipo refernce (classe, interfaccia, delegate o array) Se si devono vincolare più argomenti, servono più clausole where class Test<T,U> where U : struct where T : E, new() { } Un parametro di tipo di un'interfaccia (o delegate) generica può essere: - out, può essere usato solo come tipo di ritorno. - in, può essere usato come tipo per i parametri e nei vincoli Esempi: interface IEnumerator<out T> { bool MoveNext(); T Current {get;} } interface IComparer<in T> { int Compare(T left, T right); } delegate TResult Func<in TArg, out TResult> (Targ arg); Non ci sono funzioni/variabili globali (al più membri statici) Numero variabile di parametri: params T [] invece di T... Gli array possono essere "jagged" per sempio: int[][] myarray = new int[2][]; myarray[0]=new int[3]; myarray[0]=new int[9]; Ma ci sono anche gli array bidimensionali: int[,] myArray = new int[,]{1,2,3},{4,5,6}}
  12. Cos è CURL e a cosa Serve? cURL è un comando che serve per scriptare, cioè per scrivere degli script per trasferire dei dati, è usato nelle televisioni, nelle automobili, in una notevole varietà di dispositivi. Viene usato per le comunicazioni attraverso la rete. cURL è un tool da linea di comando quindi si può usare al di fuori di PHP, è uno strumento di networking, per interagire con sistemi remoti e ottenere delle risposte. Ci permette per esempio a Scaricare una pagina web: <?php $handle = curl_init(); $url = "...url qui..."; // Set the url curl_setopt($handle, CURLOPT_URL, $url); // Set the result output to be a string curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); $output = curl_exec($handle); curl_close($handle); echo $output; ?> curl_init() inizializza la sessione; curl setopt() opzioni della sessione; CURLOPT_URL connessione verso un dominio web; CURLOPT_RETURNTRANSFER trasferito come stringa; curl_exec() esegue la sessione con tutti i parametri; curl_close() chiude la connessione Scaricare un file remoto: <?php // Remote file $url = "https://google.it/images/google.jpg"; // Local file $file = "img.jpg"; $handle = curl_init(); // Open the local file for writing $fp = fopen($file, "w"); curl_setopt_array($handle, array(CURLOPT_URL=> $url,CURLOPT_FILE => $fp, CURLOPT_HEADER => true )) curl_exec($handle); curl_close($handle); fclose($fp); ?> CURLOPT_URL richiamo un url in remoto; CURLOPT_FILE file nel quale scrivere; Per gestire gli errori $responseCode = curl_getinfo($handle, CURLINFO_HTTP_CODE); $responseType = curl_getinfo($handle, CURLINFO_CONTENT_TYPE); if (curl_errno($handle)) { print curl_error($handle); } Inviare dati in POST via cURL Possiamo compilare un form di registrazione attraverso cURL passando in POST i valori: <?php $handle = curl_init(); $url = "https://localhost/saw/registration.php"; // Array with form fields names and values $postData = array( 'firstname' => 'Mario', 'lastname' => 'Mar', 'email' => '[email protected]', 'pass'=>'aaa', 'confirm'=>'aaa' ); curl_setopt_array($handle, array( CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $postData, CURLOPT_RETURNTRANSFER => true )); $data = curl_exec($handle); curl_close($handle); echo $data; ?> Gestire i cookie con cURL <?php $handle = curl_init(); $url = "...."; $file = "cookie.txt"; curl_setopt_array($handle, array(CURLOPT_URL => $url, CURLOPT_COOKIEFILE => $file, CURLOPT_COOKIEJAR => $file, CURLOPT_RETURNTRANSFER => true,)); $data = curl_exec($handle); curl_close($handle); ?> TRANSAZIONI Operazioni che scrivono sul database, come inserimento modifica e cancellazione, quando si modifica per esempio bisogna assicurarsi che se ci sono delle interazioni concorrenti non si diano fastidio tra di loro. Per esempio una banca che deve spostare i soldi da un conto corrente all'altro, richiede 2 operazioni uno il prelievo a l'altro incremento di un altro saldo, se succede qualcosa nel mezzo dell'operazione vuol dire che non va bene. Ci vengono in aiuto le transazioni: Iniziare la transazione Eseguire le query Se c'è Commit si finisce la transazione Se c'è stato un errore si fa il Rollback si riporta indietro. MySQLi e Transazioni L'estensione MySQLi introduce nuove funzioni per sfruttare le caratteristiche transazionali di MySQL Queste funzioni sono equivalanti ai comandi SQL START TRANSACTION (oppure BEGIN) COMMIT ROLLBACK Nota: per implementare le transazioni le tabelle del database devono essere di tipo InnoDB, BerkeleyDB, Falcon /* set autocommit to off */ $con->autocommit(FALSE); /* Insert some values */ $con->query("INSERT ..."); $con->query("UPDATE ..."); /* commit transaction */ $con->commit(); Vedi: http://www.php.net/manual/en/mysqli.commit.php Se le cose non vanno a buon fine si può tornare indietro usando il rollback /* rollback */ $con->rollback(); Vedi: http://php.net/manual/it/mysqli.rollback.php . Supponiamo di avere una tabella che memorizza le informazioni dei conti corrente di una banca . Se prendiamo dei soldi da un conto e li depositiamo su un altro conto dobbiamo assicurarci che entrambe le operazioni vadano a buon fine, altrimenti si perde del denaro . Ci vogliono due query di UPDATE che devono andare entrambe a buon fine, altrimenti bisogna riportare tutto nella situazione iniziale $query = "UPDATE contocorrente SET saldo = saldo - ? WHERE numeroconto=?"; $query = "UPDATE contocorrente SET saldo = saldo + ? WHERE numeroconto=?"; DATABASE ABSTRACTION LAYER Sono delle librerie che offrono dei metodi per interagire con il database, bisogna installarli, quella più usata oggi è PDO (PHP Data Object), indipendentemente dal DB che c'è dietro il codice funziona lo stesso, grazie alla libreria nativa del dbms. Per la connessione al database si crea un'istanza della classe PDO Il costruttore accetta come primo parametro una stringa nella quale si specifica il tipo di DBMS cui si vuole accedere (DSN = Data Source Name) <?php $conn = new PDO("mysql:dbname=$dbname;host=$host", $username, $password); ?> <?php $conn = new PDO("pgsql:dbname=$dbname;host=$host", $username, $password); ?> Vedi: http://www.php.net/manual/en/class.pdo.php Per chiudere la connessione al database <?php $conn = null ?> Gli errori sono gestiti tramite blocchi try/catch <?php try { $conn = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass); } catch(PDOException $e) { echo $e->getMessage(); } ?> Per tutte le altre operazioni si usano gli stessi metodi indipendentemente dal DBMS <?php $id = ... $name = .. $stmt = $conn->prepare("SELECT * FROM user WHERE id=? AND name=?") $stmt->bindParam(1, $id, PDO::PARAM_INT); $sth->bindParam(2, $name, PDO::PARAM_STR, 40); $stmt->execute(); ?> Sintassi alternativa $stmt = $conn->prepare("SELECT * FROM user WHERE id = :id AND name = :name"); Per tutte le altre operazioni si usano gli stessi metodi indipendentemente dal DBMS <?php $stmt->setFetchMode(PDO::FETCH_NUM); while ($row = $stmt->fetch()) { print $row[0] . "\t" . $row[1] . "\t" . $row[2] . "\n"; } ?> PDO::FETCH_ASSOC PDO::FETCH_BOTH PDO::FETCH_OBJ ecc. INVIO EMAIL via PHP PHP mette a disposizione la funzione mail() per inviare messaggi di posta elettronica MA funziona solo se sul server è installato un programma per l'invio delle email PHPMailer è una libreria da installare e configurare per inviare email dal vostro server. Potete installare PHPMailer Istruzioni qui: http://www.sitepoint.com/sending-emails-php-phpmailer/ HTTPS HTTP (HTTP e SSL/TLS) è obbligatorio, è un protocollo che crea un tunnel di sicurezza, tutti i dati che vanno in rete sono protetti da un livello di sicurezza, se qualcuno ci vuole rintracciare non lo può fare. Il certificato del server si può creare usando https://letsencrypt.org/ Al giorno d'oggi Google non indicizza più i siti senza questo protocollo di sicurezza ma sono essenziali per aumentare la priorità nei siti di ricerca. sFTP Per collegarsi ad un server si utilizza il protocollo sftp, Filezilla è un client grafico, semplice e molto facile da utilizzare per trasferire file da un client a server web. .
  13. Abbiamo visto come interagire con il database, e i passaggi da fare, per connettersi e per fare il fetch dei dati con select. Ora andiamo a vedere quello che ci manca come modificare e cancellare dati nel database. Operazioni CRUD E' un acronimo quando si gestiscono dei dati e rappresenta le 4 operazioni fondamentali che si possono fare sulle applicazioni che usano un database: Create: corrisponde ad INSERT (registration.php è una pagina pubblica) Read: corrisponde a SELECT (login.php qui si creano le variabili di sessione; show_profile.php qui si controllano le variabili di sessione) Update: corrisponde a UPDATE (update_profile.php servono le variabili di sessione) Delete: corrispodne a DELETE (delete_user servono le variabili di sessione) Modifica Profilo Regola importante: campi pre-compilati con i dati già memorizzati nel database Raccoli i dati, si deve impostareuna query SQL con comando UPDATE Spesso nella query si usa l'ID dell'utente da modificare Cancellazione utente Si usa la query di DELETE Spesso si usa l'ID dell'utente da cancellare Anche in questo caso bisogna fare attenzione a non cancellare utenti a caso.. PREAPARED STATEMENT Risolvono un problema arcinoto e continua ad esistere ovvero i SQL INJECTION, l'attacante invece di inserire in un form web (nome, cognome, ecc..) va ad inserire anche dei frammenti di codice sql che possono essere mandati in esecuzione verso il database se l'applicazione web non è fatta bene, prende i dati dall'esterno e non valida i dati in entrata. An injection of code happens when an attacker sends invalid and untrusted data to the application as part of a command or query. The attacker has the malicious intention to trick the application into executing unintended behavior to collect data or create damage. Source: https://cai.tools.sap/blog/top-10-web-security-vulnerabilities-to-watch-out-for-in-2019/ Le query come quelle viste fino ad ora, per es. $query = "SELECT * FROM user WHERE name='" . $name . "' AND surname='" . $surname . "'"; che combinano - codice SQL - input fornito dall’utente sono potenzialmente pericolose se i dati forniti in input non sono opportunamente validati Per risolvere a questo problema possiamo usare i Prepared Statement, sono delle caratteristiche che permettono di spezzare in due le interrogazioni mysql, che possono aiutare in questo problema. Rispetto alle query SQL standard, i prepared statement - vengono eseguiti più volte, per valori diversi dei parametri: prima il DBMS prepara il piano di esecuzione della query, e poi si possono avere esecuzioni multiple, per valori diversi dei parametri - sono “robusti” rispetto a SQL injection, perché i valori dei parametri sono trasmessi in un secondo momento e non sono usati nella costruzione della query MySQLi e Prepared Statement MySQL supporta i prepared statement, sono necessari 2 passi: Prepare: si scrive un template con dei parametri (placeholder) che viene inviato al DBMS. Il DBMS esegue il controllo sintattico e inizializza le risorse per gli usi successivi Execute: il client invia i valori dei parametri al server che esegue la query sfruttando le risorse precedentemente allocate Prepare - mysqli_prepare, mysqli::prepare $stmt = mysqli_prepare($con, "SELECT * FROM user WHERE email=?"); o $stmt = $con->prepare("SELECT * FROM user WHERE email=?"); Vedi: http://php.net/manual/it/mysqli.prepare.php Bind parameter mysqli_stmt_bind_param, mysqli_stmt::bind_param mysqli_stmt_bind_param($stmt, 's', $email); $email = “[email protected]”; o $stmt->bind_param('s',$email); $email = “[email protected]”; Vedi: http://www.php.net/manual/it/mysqli-stmt.bind-param.php Execute mysqli_stmt_execute, mysqli_stmt::execute mysqli_stmt_execute($stmt); o $stmt->execute(); Al termine si deve chiudere lo statement mysqli_stmt_close($stmt); o $stmt->close(); Ottenere il risultato $res=mysqli_stmt_get_result($stmt); o $res = $stmt->get_result(); $row = $res->fetch_assoc(); Per le query di SELECT viene restituita una risorsa con i record (0,1,...) selezionati in caso di successo, FALSE in caso di fallimento TRUE (successo) o FALSE (fallimento) per le altre query https://www.php.net/manual/en/mysqli-stmt.get-result.php
  14. Interazione con Database Andiamo ad introdurre il terzo elemento nelle nostre applicazioni web, abbiamo visto il web client, che faceva delle richieste e riceveva delle risposte, poi sul web server (apache+php) che via script possiamo generare pagine dinamiche. Ci manca il database server dove possiamo registrare tutti i dati che ci interessano salvare in un database. Abbiamo Mysql, che è stato acquistato da Oracle, la nuova versione opensource è nota come Mariadb, che si è fatto conoscere ultimamente ed è uguale a Mysql. Quindi ricapitolando abbiamo il web server con apache e php e ora anche mysql per formare un server completo, sia offline con XAMPP e sia online attraverso i server dedicati, condivi o vps. Mysl command line client Tramite la shell (terminale) possiamo interagire con il server mysql: mysql -h localhost -u username -p localhost è il server, in questo caso siamo in locale username è il nome dell'utente e -p è la password premiamo invio e ci chiederà di inserire la password. Bisogna sapere i diversi comandi per interagire con il server mysql da linea di comando, eccone alcuni: show databases; vi mostra tutti i database già esistenti use phpmyadmin; per usare il database phpmyadmin show tables; mostra tutte le tabelle di phpmyadmin describe pma_users; mostra la struttura della tabella select username from pma_users; mostra i record di pma_users nella tabella username MYSQL: tabelle InnoDB e MyISAM Abbiamo diversi motori per salvare il tipo di tabelle diverse, abbiamo diverse caratteristiche, InnoDB è il default attualemnte. MyISAM era in passato di default ed era ottimizzato per siti web che avevano molte letture ma non sono efficienti in caso di scrittura. Quindi se abbiamo un sito web dove dobbiamo solo leggere da Mysql possiamo usare MyISAM, mentre se dobbiamo scrivere molto nel DB possiamo usare di default InnoDB. Se abbiamo più utenti che scrivono nei DB, abbiamo i problemi di Lock, DBMS mettono in piedi i meccanismi di Lock, InnoDB è molto più sofisticato, ha un row-level locking, a livello di righe mentre MyIsam ha un table-level locking, per le operazioni di scritture InnoDB è più efficiente permette scritture concorrenti purchè agisca su righe diverse. mentre MyIsam blocca l'intera tabella e quindi nessuno può scrivere se la tabella è bloccata da un utente. MyIsam può costruire degli indici per la ricerca di tipo FULLTEXT mentre InnoDB non lo aveva fino alla versione Mysql 5.6. InnoDB permette di implementare la transazioni, implementa i controlli di integrità su chiavi esterne. MYSQL: UTENTI Un server Mysql può gestire più utenti e più database. L'utente root deve essere usato solo per l'amministrazione del DBMS. Al momento dell'installazione si deve specificare la password per l'utente root! Per ogni utente che deve usare il sistema (ancora meglio, per ogni database) si dovrebbe definire un utente Mysql. Privilegi su database e tabelle Un utente o un processo dovrebbe avere il minimo privilegio per fare il suo task. MYSQL: Controllo dell'accesso Il controllo dell'accesso in MySql si svolge in due passi Controllo delle credenziali dell'utente Mysql Se le credenziali sono OK, per ogni istruzione SQL, il server Mysql verifica se l'utente ha i privilegi sufficienti. Mysql ha un sistema di privilegi che per ogni utente permette di specificare quali operazioni può fare, si usa il comando grant, e si ha una tabella che si chiama grant tables. MySql fornisce 4 livelli di privilegi: - Global, Database, Table, Column Per assegnare (cancellare) un privilegio ad un utente si usa il comando GRANT (REVOKE) GRANT <privileges> [columns] ON <item> TO <username> [IDENTIFIED BY ‘<password>’] [WITH GRANT OPTION]; Creazione utente/db CREATE USER '<sawuser>'@'localhost' IDENTIFIED BY '<sawpwd>'; CREATE DATABASE <sawdb>; GRANT select, insert, update, delete, index, alter, create, drop ON <sawdb>.* TO <sawuser> IDENTIFIED BY ‘<sawpwd>’; FLUSH PRIVILEGES; MySQL permette di definire privilegi per l'utente generico, privilegi per l'amministratore, e dei privilegi speciali Per l'utente generico si possono ad esempio specificare i seguenti privilegi – SELECT, INSERT, UPDATE, DELETE, INDEX, ALTER, CREATE, DROP INTERAZIONE MYSQL COME FARE PHP ha delle librerie che interagiscono con Mysql. Per accedere ad un database da una applicazione web, i passi fondamentali sono i seguenti: Filtrare i dati in arrivo dal client Stabilire una connessione e selezionare un database Preparare la query Eseguire la query Ottenere il risultato Formattare il risultato per l'utente chiudere la connessione Abbiamo due librerie principali: - PHP's mysqli Extension, libreria nativa - PHP Data Objects (PDO), database abstraction layer, permette di lavorare su database diversi senza cambiare il codice. 1. Controllare i dati in arrivo $nomevar=$_POST['...']; $nomevar=trim($nomevar); mysqli_real_escape_string(); La funzione trim(), rimuove gli spazi o tab e \n a fine o inizio stringa. Con il database possiamo usare la funzione sopra che pulisce i caratteri speciali. 2. Stabilire la connessione //Stile procedurale $con = mysqli_connect (“localhost”,“name-of-user”,“password-of-user”,”db-name”); if (mysqli_connect_errno($con)) { echo "Failed to connect to MySQL: " . mysqli_connect_error($conn); } //Stile object oriented $con = new mysqli( “localhost”,“name-of-user”,“password-of-user”,”db-name” ); // Per il controllo dell’errore vedi: // https://www.php.net/manual/en/mysqli.construct.php 3. Preparare la query: SELECT In questo primo esempio la query "mischia" codice SQL e dati in arrivo dal browser $query = “SELECT * FROM user WHERE name='” .$name. “' AND surname='” .$surname. “'”; Attenzione! La query viene passata al database e bisogna ricordare l'escape dei dati di input per evitare errori/attacchi 4. Eseguire la query //Stile procedurale $res = mysqli_query($con,$query); //Stile object oriented $res = $con->query($query); In caso di SELECT viene restituita una risorsa che contiene i dati estratti dalla query False in caso di errore 5. Ottenere il risultato //Stile procedurale $row = mysqli_fetch_assoc($res); //Stile object oriented $row = $res->fetch_assoc(); come array: $row = mysqli_fetch_array($res,flag); $row = $res->fetch_array(flag); come oggetto: $obj = mysqli_fetch_object($res); $obj = $res->fetch_object(); Sono disponibili altre funzioni che possono essere usate dopo l'esecuzione delle query per capire se le cose sono andate a buon fine // SELECT $rowcount=mysqli_num_rows($res); $rowcount=$res->num_rows(); // INSERT, UPDATE, REPLACE, DELETE $num = mysqli_affected_rows($con); $num = $con->affected_rows(); 6. Formattare il risultato Si deve produrre codice HTML che verrà restituito al client che ha fatto la richiesta, ad esempio nel caso di SELECT, per ogni tupla restituita dal DB si potrà avere: // leggo i valori nella tupla $attr1=htmlspecialchars($row[1]); $attr1=htmlspecialchars($row[2]); ... // li restituisco in output echo “<tr>”; echo “<td>$attr1</td>\n”; echo “<td>$attr2</td>\n”; echo “</tr>”; ... 7. Liberare la memoria mysqli_free_result($res); o $res->free(); True in caso di successo, False in caso di errore 8. Chiudere la Connessione mysqli_close($con); o $con->close(); Preparare la query: INSERT In questo secondo esempio la query "mischia" codice SQL e dati in arrivo dal browser $query = "INSERT INTO users (id_user,name,surname,username,...) VALUES (NULL,'” . $name . “','” . $surname . “','” . $email . “'...)”; Dopo aver eseguito la query si può verificare il numero di record coinvolti nell'operazione $num = mysqli_affected_rows($con); o $num = $con->affected_rows(); Le query di UPDATE e DELETE sono del tutto analoghe
  15. A cosa servono i Cookie? Il web server non ha "memoria" delle comunicazioni HTTP successive, anche se arrivano dallo stesso client. Nelle richieste HTTP ci sono i parametri che contengono le risorse che state cercando, immagini, video, file statici o sempre di più file dinamaci, in PHP. Questo protocollo non ha memoria di comunicazioni successive, e quindi non mantiene lo stato, se ci sono siti con il login bisogna mantenere la memoria. Per questo motivo, per realizzare applicazioni web complesse, sono stati introdotti altri meccanismi Cookie, introdotti negli anni 90 da Netscape per gestire il carrello. Access Control, controllo degli accessi implementati sul server Session Control, realizzare sessioni tengono traccia dell'utente durante le sue interazioni COOKIE: DEFINIZIONE “ ... a cookie is a bit of text, containing some unique information, that web servers send in the HTTP header. The client's browser keeps a list of cookies and web sites. When the user goes back to a web site, the browser will automatically return the cookie, provided it hasn't expired ... ” Vedi: http://en.wikipedia.org/wiki/HTTP_cookie I Cookie sono una sequenza di caratteri, che contiene informazioni univoche, vi spedisce in uno dei header HTTP. Il browser quando riceve questa sequenza lo salva e ne tiene traccia, quando torniamo su questo sito il browser ha già il cookie registrato, sempre che non sia scaduto perchè ha una durata. COOKIE: FORMATO Un cookie è una stringa di testo formata da diverse parti (separate da ; ) alcune opzionali: Name = <VALUE>; <- obbligatorio Expires = <DATE>; possono avere una data, se non si specifica dura finche non si chiude il browser. Path = <PATH>; per quale insieme di pagine è valido il cookie Domain = <DOMAIN_NAME>; nome del sito che rilascia il cookie Secure -> se è sicuro il trasferimento https:// HttpOnly -> non sono leggibili via javascript SameSite -> non può essere inviato ad altri siti COOKIE: RISPOSTA HTTP Un cookie viene memorizzato nel browser se il server include l'header Set-Cookie: come parte di una risposta HTTP Un ipotetico cliente associato questa stringa, e con scadenza il 16 dicembre: Set-Cookie: customer=56FRP13456UYH; domain=.trenitalia.com; expires=Wednesday, 16-Dec-20 ATTENZIONE: non mettere mai dati sensibili nei cookie, perchè si trovano sul client e sono modificabili Quando un utente torna su un sito che ha già visitato e che gli ha "lasciato" un cookie, il suo browser invia automaticamente il cookie (la coppia name=<VALUE>) come parte della sua richiesta HTTP Cookie: customer=56FRP13456UYH; Un browser dovrebbe essere in grado di memorizzare almeno 300 cookie al massimo 4 KB per cookie un massimo di 20 cookie dallo stesso server (o dominio) Come creare i cookie in PHP? setcookie (string name, string value, int expire, string path, string domain, bool secure, bool httponly) Vedi: http://www.w3schools.com/php/php_cookies.asp http://www.w3schools.com/php/func_http_setcookie.asp Quando si torna su un sito che ha già lasciato un cookie, il browser invia nell'header della richiesta HTTP il valore del cookie Sul server questo valore può essere letto in $_COOKIE $HTTP_COOKIE_VARS Si può portare la data di scadenza del cookie al passato Si può assegnare al cookie il valore nullo <?php // if cookie exists if (isset($_COOKIE["mycookie"])) { read the value of the cookie return a personalized welcome back message } else { show registration module } ?> Creazione di un cookie <?php ... $cname=”mycookie”; $cvalue = “cookie value here”; $cexpires = mktime(0,0,0,01,01,2021); setcookie($cname,$cvalue,$expires); ?> Cancellazione del cookie <?php // set the expiration date to one hour ago setcookie("mycookie", "", time()-3600); ?> Sono impostati da un sito web diverso da quello che si sta attualmente visitando. Sono usati dagli inserzionisti pubblicitari che li utilizzano per tenere traccia delle visite su tutti i siti sui quali offrono i propri servizi Secondo quanto previsto dal Regolamento generale sulla protezione dei dati personali (GDPR) dell'UE, ogni sito web deve permettere agli utenti europei dei controllare l'attivazione dei cookie e dei tracker che raccolgono i loro dati personali. E' possibile disabilitare i cookie (soprattutto di terze parti) ma spesso i siti web che vivono di pubblicità smettono di funzionare Per esempio si può usare AdBlock https://it.wikipedia.org/wiki/AdBlock Per maggior informazioni sui cookie, vi consiglio la pagina Using HTTP cookies. ESEMPIO PRATICO Index.php (pagina principale con i Cookie, se si accede direttamente non ha nessun stile CSS e quindi non è formattato; issset() funzione già vista; il nome stile del Cookie; explode() già visto per dividere la stringa; e poi apriamo il tag body e tramite la posizione degli array aggiorniamo i css) <!DOCTYPE html> <html lang="it"> <head> <title>Homepage</title> <style> <?php if (isset($_COOKIE["stile"])) { $val = $_COOKIE["stile"]; $prop = explode("|", $val); echo "\tbody {\n"; echo "\t\t$prop[0];\n"; echo "\t\t$prop[1];\n"; echo "\t\t$prop[2];\n"; echo "\t}\n"; } ?> </style> </head> <body> <h1>Lorem Ipsum</h1> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus sem tellus, sagittis eu molestie non, venenatis vel lectus. Etiam sapien sem, efficitur ut lacus at, volutpat sodales nibh.</p> <p> Proin dapibus risus congue, cursus libero sit amet, bibendum lectus. Morbi a hendrerit mi. Phasellus feugiat nulla eros, pellentesque congue felis dictum eu. In hac habitasse platea dictumst.</p> <p><a href="personalize.php">Vai alla pagina di personalizzazione</a></p> </body> </html> Personalize.PHP (Abbiamo il Form per personalizzare il documento sopra con il metodo POST) <!DOCTYPE html> <html lang="it"> <head> <title>Personalizza le tue pagine con i cookies</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div id="mydiv"> <form id="myform" action="setcookie.php" method="POST"> Text color: <input type="color" name="color"> Background: <input type="color" name="background-color"> Font: <select name="font-family"> <option value="0">Select font family</option> <option value="Arial">Arial</option> <option value="Arimo">Arimo</option> <option value="Verdana">Verdana</option> <option value="Ubuntu">Ubuntu</option> </select> <br> <input type="submit" value="Submit"> </form> </div> </body> </html> Setcookie.PHP (Prendiamo i dati dal Form sopra e creiamo il Cookie con nome, durata e la funzione setcookie(); la funzione header() ci reinderizza nella pagina principale index.php) <?php $value = ""; if (isset($_POST["color"]) & $_POST["color"] != "#000000") $value .= "color: " . $_POST["color"] . "|"; else $value .= "color: black|"; if (isset($_POST["background-color"]) & $_POST["background-color"] != "#000000") $value .= "background-color: " . $_POST["background-color"] . "|"; else $value .= "background-color: white|"; if (isset($_POST["font-family"]) & $_POST["font-family"] != "0") $value .= "font-family: " . $_POST["font-family"] . "|"; else $value .= "font-family: serif|"; $name = "stile"; $expires = mktime(0, 0, 0, 01, 01, 2021); setcookie($name, $value, $expires); header("Location: index.php"); exit; ?> A cosa servono le Sessioni? La sessione è importante per tenere traccia di quello che stiamo facendo, a differenza dei Cookie che sono salvate su browser, non bisogna mettere informazioni riservate. Il controllo di sessione permette di tener traccia dell'utente durante la sua interazione con un sito web. Cosi da non richiedere ogni volta username e password ma vengono memorizzati e finche non scade l'utente può navigare nella sessione. Per gesitre il controllo di sessione si usa l'array superglobale $_SESSION Inoltre in PHP si associa ad ogni visitatore un identificatore univoco, chiamato session ID. Viene memorizzato in un Cookie nell header e viene scambiato avanti e indietro per tutta la durata, cosi il web server sa che quell'utente è sempre lui. Vedi: http://www.w3schools.com/php/php_sessions.asp SESSIONE COME FARE? Iniziare una sessione Creare le variabili di sessione Usare le variabili di sessione Distruggere le variabili di sessione e chiudere la sessione sessione_start(); Verifica se l'utente ha già un identificatore di sessione Se non lo trova, ne crea uno, altrimenti rende accessibili le variabili di sessione già create in precedenza per quell'utente Quando si usano le sessioni è obbligatorio iniziare tutti gli script delle pagine riservate con session_start(). $_SESSION["myvar"] = <valore>; La variabile di sessione viene creata assegnando una chiave all'array superglobale $_SESSION e un valore corrispondente. La variabile esiste e viene "tracciata" fino a quando non si termina la sessione. Con isset() si verifica se la variabile di sessione esiste. if (isset($_SESSION["myvar"])) { ... } else { ... } Se si, l'utente è autorizzato a proseguire, altrimenti lo si rimanda alla pagina di login. unset($_SESSION["myvar"]); La sessione esiste ancora ma la variabile di sessione myvar non è più registrata come variabile di sessione. session_destroy(); Cancella l'identificatore di sessione. $_SESSION = array(); Assegnare un array vuoto alla sessione. <?php session_start(); echo "SID: " . session_id(); ?> ESEMPIO: SID: 0a777aa640f1bad7ac3f788065a99ba6 Nella fase di autenticazione Si verifica la correttezza dei dati dell'utente Se l'utente è autorizzato, si creano una o più variabili di sessione Si presentano i servizi dell'area riservata <?php session_start(); /* check user data */ if <login OK> { $_SESSION[“myvar1”] = ...; $_SESSION[“myvar2”] = ...; $_SESSION[“myvar3”] = ...; /* build list of services */ } else { echo “ <h2>You cannot access to these services, check your data</h2>\n ”; } ?> Durante la navigazione nell'area riservata Tutti i file che offrono servizi devono controllare le variabili di sessione, non basta il controllo sul primo file! <?php session_start(); if (!isset($_SESSION[“myvar1”])) { echo “<h2>Access denied</h2>\n”; <present login module>; } else { /* show reserved page */ } ?> PHP7: HEADER() Permette di inviare header HTTP al client Importante: dovrebbe essere invocata prima di restituire al client dati in output, basta anche un solo spazio vuoto (o una riga vuota nel file PHP cui corrisponde il carattere "\n") per causare un errore. header('Location: URL') // redirect header('Content-type: image/jpg') // MIME type header('Cache-Control: no-cache, must-revalidate') // no cache header('Expires: Mon, 26 Jul 2010 05:00:00 GMT') // date in the past Nota: bufferizzazione output PHP invia al client qualunque output non appena disponibile. E' possibile salvare temporaneamente quello che dovrebbe essere restituito in output fino a quando non viene detto esplicitamente di spedirlo. Così facendo, header e dati vengono inviati in modo corretto anche se alcuni header sono stati creati dopo i primi output HTML Per abilitare questa funzionalità si può usare la funzione ob_start() oppure si può attivare la direttiva output_buffering = 4096 // 4096 sono i byte bufferizzati Access Control HTTP è stateless e nasce per lo scambio di risorse. Abbiamo problemi di autorizzazione, e come visto sopra ci viene in aiuto la gestione delle sessioni e ancora prima quella dei Cookie. Nel caso di risorse ad accesso riservato è necessario usare degli accorgimenti Esistono diverse tecniche, più o meno semplici da implementare, più o meno sicure... URL nascoste Controllo basato sull'indirizzo IP o sul nome di dominio Controllo basato sull'identità dell'utente I controlli basati sull'identità dell'utente o sull'indirizzo IP possono essere demandati al server web sfruttando la Basic Authentication di HTTP Vediamo il caso degli utenti Quando si cerca di accedere a informazioni protette - il browser visualizza una finestra di dialogo che richiede le credenziali all'utente - le credenziali vengono scambiate tra browser e server per tutta la durata dell'interazione Risposta HTTP di tipo 401: HTTP/1.1 401 Authorization Required Date: Tue, 04 Mar 2016 17:09:06 GMT Server: Apache/1.3.34 Ben-SSL/1.55 (Debian) PHP/4.4.4-8+etch2 mod_auth_pam/1.1.1 mod_perl/1.29 DAV/1.0.3 WWW-Authenticate: Basic realm="Restricted Area for My Server." Transfer-Encoding: chunked Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <HTML><HEAD><TITLE>401 Authorization Required</TITLE></HEAD> <BODY> <H1>Authorization Required</H1>This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.<P></BODY></HTML> Si può creare un file di testo .htaccess nella directory che si vuole proteggere e specificare delle direttive Vedi: http://httpd.apache.org/docs/current/howto/auth.html AuthType Basic AuthName “Restricted Area for My Server” AuthUserFile /absolutepath/nomefilepwd Require valid-user * invece di scrivere valid-user, si possono elencare gli utenti che possono accedere, oppure un gruppo di utenti Le credenziali degli utenti possono essere salvate in un file di testo, specificando la direttiva AuthBasicProvider file Con il file di testo ci sono problemi di efficienza (il file viene letto per ogni accesso alle risorse nell'area protetta) e si possono anche usare formati di storage come dbm e dbd, o LDAP AuthBasicProvider dbm AuthBasicProvider ldap Il file delle password si crea con il comando htpasswd (-c si deve usare solo la prima volta che si crea il file delle password) htpasswd –c nomefilepwd nomeuser New password: ********* Re-type new password: ********* Nota: Il file .htaccess e quello delle password devono essere leggibili dal web server (chmod 644) Per ogni accesso ad una pagina protetta, il server deve leggere dalla richiesta HTTP le credenziali e poi accedere a - file .htaccess - file/database/LDAP per la password Se il numero degli utenti cresce, questo meccanismo di autenticazione diventa inefficiente
  16. Le password degli utenti non si devono MAI memorizzare in chiaro. Molti attacchi sul web hanno lo scopo di rubare le password degli utenti https://haveibeenpwned.com/ Su questo sito inserendo il vostro indirizzo email, il servizio vi dice se è stato trovato in qualche attacco (Databreach), molti siti web non sicuri vengono attaccati e rubati i dati sensibili, il database degli iscritti contenenti email e password. Su questo servizio vengono catalogati tutti gli attacchi informatici e se esiste la nostra email in un db ce lo mostra. In caso di furto, bisogna garantire che l'attaccante non riesca a decifrare le password. Oggi per rispettare le regole del GDPR bisogna proteggere i dati sensibili (e le password lo sono). PHP7: GESTIONE DELLE PASSWORD Su php le cifriamo, ed offre funzioni di HASH, prendo una stringa le applico la funzione e ricevo un'altra stringa. /* User's password. */ $password = 'mysecretpassword'; /* MD5 hash */ $hash = md5($password); /* SHA1 hash */ $hash = sha1($password); Queste funzioni sono DEPRECATE, non bisogna usarle più, perché non sono più sicure. Gli algoritmi MD5 e SHA sono troppo deboli per la potenza di calcolo odierna. Gli hash prodotti da questi algoritmi sono vulnerabili ad attacchi "rainbow table" e ad attacchi a dizionario: - https://crackstation.net/ (a volte basta Google!) - https://en.wikipedia.org/wiki/List_of_the_most_common_passwords La funzione che dobbiamo usare, che viene consigliata in tutti i manuali è la funzione PASSWORD HASH, con due parametri, il primo è la password e il secondo è PASSWORD_DEFAULT, specifica quale funzione di cifratura usare. /* User's password. */ $password = 'mysecretpassword'; $hash = password_hash($password, PASSWORD_DEFAULT); Questa funzione usa un "sale" che viene aggiunto alla password per evitare attacchi rainbow table o a dizionario. Il "sale" è una stringa generata in modo casuale (da PHP!). Per verificare le password degli utenti si deve usare la funzione password_verify() ESEMPIO PRATICO Vediamo come utilizzare quello che abbiamo imparato con un esempio di Form di Registrazione, con input di nome, cognome, email e password, e a salvare i dati su un File in locale: Registrazione.HTML (usiamo il metodo POST per inviare i dati) <!DOCTYPE html> <html lang="it"> <head> <title>Sign-up</title> <link rel="stylesheet" type="text/css" href="style.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> </head> <body> <div id="mydiv"> <form id="myform" action="registration.php" method="POST"> <i class="fas fa-file-signature"></i> <input type="text" class="no-outline" id="firstname" name="firstname" placeholder="Firstname"><br> <i class="fas fa-file-signature"></i> <input type="text" class="no-outline" id="lastname" name="lastname" placeholder="Lastname"><br> <i class="fas fa-at"></i> <input type="email" id="email" class="no-outline" name="email" placeholder="E-mail"><br> <i class="fas fa-key"></i> <input type="password" class="no-outline" id="pass" name="pass" placeholder="Password"><br> <i class="fas fa-key"></i> <input type="password" class="no-outline" id="confirm" name="confirm" placeholder="Confirm password"> <br> <input type="submit" value="Submit"> </form> </div> </body> </html> Rregistrazione.PHP (abbiamo la funzione isset() che vede se il campo è stato settato o è vuoto; la funzione trim() elimina gli spazi vuoti o dei caratteri all’inizio e alla fine di una stringa; filter_var() applica un filtro ad una variabile in questo caso per verificare un email in forma esatta; <!DOCTYPE html> <html lang="it"> <head> <title>Sign-up</title> </head> <body> <?php if (!isset($_POST["firstname"]) || !isset($_POST["lastname"]) || !isset($_POST["email"]) || !isset($_POST["pass"]) || !isset($_POST["confirm"])) { echo "<p>Check input data, some are missing</p>\n"; echo "</body>\n</html>"; exit(); } $firstname = trim($_POST["firstname"]); $lastname = trim($_POST["lastname"]); $email = trim($_POST["email"]); $pass = trim($_POST["pass"]); $confirm = trim($_POST["confirm"]); if (empty($firstname) || empty($lastname) || empty($email) || empty($pass) || empty($confirm)) { echo "<p>Check input data, some are missing</p>\n"; echo "</body>\n</html>"; exit(); } $error = ""; if (!$email = filter_var(trim($_POST["email"]), FILTER_VALIDATE_EMAIL)) { $error .= "<p>Check e-mail format</p>\n"; } if ($pass != $confirm) { $error .= "<p>Passwords do not match</p>\n"; } if ($error) { echo $error; echo "</body>\n</html>"; exit(); } $hash = password_hash($pass, PASSWORD_DEFAULT); $line = $firstname . "|" . $lastname . "|" . $email . "|" . $hash ."\n"; $fp = fopen("mydata.txt", "a+"); fwrite($fp, $line); fclose($fp); echo "<h1>"; echo "Hello "; echo $_POST["firstname"]." ".$_POST["lastname"].",\n"; echo " your data have been registered."; echo "</h1>\n"; ?> </body> </html> Ora vediamo come fare il login sempre in HTML e poi in PHP con la registrazione di prima e i dati sul File in locale. Login.HTML (un semplice Form in html con il metodo POST) <!DOCTYPE html> <html lang="it"> <head> <title>Login</title> <link rel="stylesheet" type="text/css" href="style.css"> <link rel="stylesheet" type="text/css" href="INSERISCI URL CSS AWESOME"> </head> <body> <div id="mydiv"> <form id="myform" action="login.php" method="POST"> <i class="fas fa-at"></i> <input type="email" id="email" class="no-outline" name="email" placeholder="E-mail"><br> <i class="fas fa-key"></i> <input type="password" class="no-outline" id="pass" name="pass" placeholder="Password"><br> <br> <input type="submit" value="Submit"> </form> </div> </body> </html> Login.PHP (la funzione isset() vista in precedenza; file_get_contents() per leggere interamente il file; strpos() trova la posizione iniziale dell'email nel nostro caso; trim() vista in precedenza; substr() per prendere solo la string che ci interessa dandogli un inizio ed una fine; strlen() lunghezza della stringa ;e password_verify() di cui abbiamo parlato sopra) <!DOCTYPE html> <html lang="it"> <head> <title>Login</title> </head> <body> <?php $mail = ""; if (isset($_POST['email'])) { $mail = $_POST["email"]; } $psw=""; if (isset($_POST['pass'])) { $psw = $_POST["pass"]; } $users = file_get_contents('mydata.txt',true); $pos = strpos($users,$mail); $phash=trim(substr($users, $pos+strlen($mail)+1, 61)); if ($pver=password_verify($psw, $phash)) { echo "<h1>pass verified!</h1>"; } else { echo "<h1>pass incorrect</h1>"; } ?> </body> </html> mydata.txt (il file contenente i dati di registrazione) mario|mao|[email protected]|$2y$10$IYOaWxU5rVBqpMnSUxf1s.pKjKHGPGFuM0gXligDFGiOw/0oiHEqa maria|mea|[email protected]|$2y$10$Z7ozJ8RktrKBo0ai2YT9Fu2uzsM3XG6EolwEgZy2zgfqfSLwFHeoO Login.PHP #2 (vediamo un altro esempio con altre funzioni nuove; fopen() che prende il file; feof() legge il file fino in fondo; fgets() legge riga per riga il file; explode() legge fino al simbolo "|"; isset() che abbiamo già visto; trim() già visto; password_verify() visto sopra) <?php $file = fopen("mydata.txt","r"); while(! feof($file)) { $eriga = explode('|', fgets($file)); if (isset($eriga[2])) { if (trim($eriga[2])==$_POST["email"]) { if (password_verify($_POST["pass"], trim($eriga[3]))) { echo "Login corretto!"; } } else { echo "user o passw sbagliati"; } } } fclose($file); ?> PHP7: DATI IN ARRIVO DAL CLIENT I dati in arrivo dal client devono essere validati! PHP ha varie funzioni che permettono di testare il contenuto dei dati forniti in input. Il test dipende dalle abilità del programmatore.. SQL Injection (mysqli_real_escape_string, prepared statements) riguardano gli attacchi al database, quelli riguardanti il browser sono XSS (htmlspecialchars), e per scrittura e download su file sono i Path Traversal (confinare l'include dei file dentro la DocumentRoot), quando si creano Script bisogna imparare a difendersi ed usare le funzioni apposite. Vediamo insieme alcune funzioni sopra citate: isset($_POST[var]): true(1) se esiste e non è Null; false (0) altrimenti empty($_POST[var]): true(1) se non esiste oppure il suo valore è False; false(0) altrimenti trim($_POST[var]): toglie spazi, \n, \r, \t, \v, \0 ad inizio e fine stringa filter_var($str[,int $filter=FILTER_TYPE]): applica il filtro selezionato(regex) alla stringa htmlspecialchars($str, ENT_QUOTES[, $charset]: converte i caratteri speciali nelle entità HTML corrispondenti PHP7: PARSING INPUT Esistono delle funzioni per fare il parsing, prendono una stringa e lo convertono in intero. int($_GET['x']) converte $_GET['x'] in intero, se possibile (simile a int intval(mixed $var [, int $base = 10 ] ) ) Esempio: 12a -> 12, a12 -> 0 doubleval($_GET['x']) strval($_GET['x']) is_numeric($x) verifica se $x è un numero o una stringa PHP7: ESPRESSIONI REGOLARI Si possono usare le espressioni regolari per definire dei pattern su stringhe di testo. PHP usa le espressioni regolari di Perl e offre delle funzioni per verificare se un certo pattern occorre in una stringa. Mediante l'uso di simboli come +,?,-,^,*,[],{} si possono creare espressioni complesse per validare email, indirizzi IP, ecc. Esempi: /[0-9]{8,14}/ -> tutte le stringhe numeriche almeno 8 caratteri e massimo 14. /[a-z\s]{10,20}/ -> tutte le lettere minuscole "\s" anche li spazi e lunghe da 10 a 20 caratteri. /[a-zA-Z0-9\s]{1,}/ -> tutte le sequenze caratteri minuscole e maiuscole con numeri e spazi lunghe da 1 a nessun limite. /^.{2}$/ -> accetta solo coppie di caratteri Vediamo come fare in PHP: (preg_match() restituisce se vero o falso) <?php $str = "Ciao ciao "; $pattern = " /[a-z\s]{10,20}/ "; echo preg_match($pattern, $str); ?> ESEMPIO PRATICO Ora vediamo come fare il pattern del Codice Fiscale e la funzione preg_match(): <form method="GET" action="<?php echo $_SERVER['PHP_SELF']; ?>?codfis=<?php $_GET['codfis']?>"> <label for="codfis">Codice Fiscale:</label> <input type="text" id="codfis" name="codfis" pattern="^[a-zA-Z]{6}[0-9]{2}[a-zA-Z][0-9]{2}[a-zA-Z][0-9]{3}[a-zA-Z]$" title="codice fiscale"><br><br> <input type="submit"> </form> <?php $str = $_GET['codfis']; preg_match('/^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/i', $str, $matches); if($matches[0]==$_GET['codfis']) { echo "sintassi corretta!"; } ?>
  17. Cos è PHP e come funziona? Programmazione lato server, abbiamo un client che è un browser gestito da un utente che naviga nel web, richieste del web server, richieste HTTP, protocollo del web, se hanno le risorse cercate, le ritornano sotto forma di risposte HTTP, con l'HTML avevamo pagine statiche, di documenti, immagini e fogli di stili css. Da ora in poi avremmo delle pagine dinamiche, on the fly mediante esecuzione lato server. Script che invocato con opportuni parametri genererà una pagina e ritornerà questa pagina a chi ne ha fatto la richiesta. Il Web Server sarà composto di Apache (ne esistono altri) per la comunicazione, l'interprete PHP per la logica applicativa, Mysql per l'accesso ai dati. PHP è un linguaggio di scripting, di programmazione (con costrutti come in altri linguaggi se sapete già qualcosa), open source, server side, sviluppato per il web Il progetto inizia nel 1994 ad opera del danese Rasmus Lerdorf, diventato particolarmente popolare nella programmazione web, è possibile scrivere nel codice HTML con opportuni costrutti codice PHP. Un file con codice PHP deve essere salvato in formato testo ed estensione .php e ci penserà l'interprete a codificare il linguaggio e restituire la richiesta. PHP è HTML-embedded, cioè gli script possono essere inseriti nelle pagine HTML in cui devono produrre i loro output. Il web server riconosce le pagine PHP, distinguendole da quelle statiche, sulla base dell'estensione .php e richiama l'interprete. Il client vede solo il codice HTML generato: quindi vede cosa produce lo script ma non come arriva il risultato. Il web server è un programma che gira sulla vostra in macchina ed è in ascolto in attesa di richieste, da parte da un utente, ha solo directory specificate dall'utente in cui cercare i file richiesti, di solito in Apache è /htdocs. Il server prende il codice php lo interpreta e ne restituisce l'output, che di solito è diverso dal codice sorgente. <?php echo "<h1>"; echo "Hello"; echo "Firstname" . "Lastname"; echo "your data have been registered. "; echo "</h1> \n"; ?> Nel caso di sopra restituisce "Hello Firstname Lastname your data have been registered." PHP7: STRUTTURA LESSICALE Le istruzioni devono essere separate tra loro dal ; Commenti: es. // questo è un commento es. /* questo è un commento */ es. # questo è un commento Gli identificatori devono iniziare con il simbolo $ es. $firstname $lastname $email PHP è case sensitive, $a != $A Per gli identificatori non si possono usare le keyword del linguaggio and include break list case new class not continue or default require do return else static elseif switch extends this false true for var foreach virtual function xor global while if PHP7: VARIABILI e SCOPE Le variabili in PHP non devono essere dichiarate, basta assegnare dei valori, il linguaggio PHP non è tipato. PHP ha scope (visibilità delle variabili): local, global, static PHP7: local <?php $a=1; //global scope function test() { echo "$a"; //reference to local scope variable } test(); ?> PHP7: global <?php $a=1; //global scope $b=2; function sum() { global $a,$b; // global scope $a=$a+$b; } sum(); echo "$a"; ?> PHP7: static <?php $a=1; //global scope $b=2; function sum() { global $a,$b; // global scope //local variable, that keeps values among successive calls static $tmp; $sum = $a + $b; //local scope $tmp +=$sum; echo $sum; echo $tmp; } sum(); ?> PHP7: VARIABILI SUPERGLOBALI Variabili superglobali esistono sempre e vengono create in automatico Array di variabili automaticamente globali, ovvero disponibili in ogni scope Esistono diversi array superglobali, ognuno con una funzione diversa $GLOBALS contiene un riferimento a tutte le variabili disponibili nello scope globale $_SERVER insieme di variabili relative al server web o legate all'ambiente di esecuzione dello script corrente $_GET, $_POST, $_COOKIE, $_SESSION <?php phpinfo(); ?> Questa funzione in PHP vi dice la versione di php installata e tantissime informazioni sul vostro server, anche molte variabili su Host e server. Come per esempio la document_root (dove si trovano i vostri file fisici), e tante altre variabili d'ambiente PHP7: TIPI DI DATI Come gli altri linguaggi di programmazione anche php ha i tipi di dati, ma è debolmente tipato, perchè non si dichiara il tipo, ma queste sono Boolean, Integer, Float, String, Array, Object. Il tipo di una variabile può cambiare dinamicamente, a seconda del valore che viene assegnato ad essa. PHP7: COSTANTI Si possono definire delle costanti: define("NOMECOSTANTE", valore); Per convenzione per i nomi delle costanti si usano i caratteri maiuscoli PHP7: ISTRUZIONI Più o meno come il linguaggio C (e Javascript), aperte chiuse grafi per i blocchi, istruzioni terminano con punto e virgola, assegnazioni con uguale. Concatenazione tra stringhe: <?php $msg='Hello ' .$nome; $msg="Hello " .$nome; $msg="Hello $nome"; // solo con "..." ?> per l'output a video: <?php echo "Hello world\n"; print("Hello world\n"); print_r($_POST); ?> PHP7: DATI in arrivo dal client Ogni dato scritto dall'utente in un form, una volta spedito, viene memorizzato in una variabile PHP. I dati inviati con il metodo POST sono memorizzati nell'array $_POST[] I dati inviati con il metodo GET sono memorizzati nell'array $_GET[] Si può vedere il contenuto di questi array (e di tutti gli array associativi con print_r() In passato la direttiva register_globals=On nel file php.ini permetteva di usare lo short style($nome,$cognome) oggni deprecato. <?php $_POST['nomevar']; / //OK $_GET['nomevar']; //OK $_REQUEST['nomevar']; //medium style ?> PHP7: SALVARE DATI sul Server Esistono due meccanismi per salvare i dati in arrivo da un client file database PHP7: GESTIONE FILE Molto simile al linguaggio C, ecco le diverse funzioni per lavorare con i file: fopen() https://www.php.net/manual/en/ref.filesystem.php – fclose() - Closes an open file pointer – fgets() - Gets line from file pointer – fread() - Binary-safe file read – fwrite() - Binary-safe file write – fsockopen() - Open Internet or Unix domain socket connection – file() - Reads entire file into an array – file_exists() - Checks whether a file or directory exists – is_readable() - Tells whether a file exists and is readable – ... Per ragioni di sicurezza se si scrivono dati sensibili in un file sul server, questo deve essere salvato fuori dalla DocumentRoot <?php $filename = $_SERVER['DOCUMENT_ROOT'] . “/private/mydata.txt”; $fp = fopen($filename,”a”); ?> NOTA: il nome del file non viene MAI scelto dall’utente Se non si specifica alcun pathname, il file viene creato nella stessa directory dello script PHP che apre il file stesso DOCUMENT ROOT Se volete provare in locale potete usare XAMPP, un programma che comprende tutto il necessario per il web server, con php, mysql e apache. se usate linux la cartella document root sara htdocs. Se si ottiene un errore come quello seguente si deve verificare che lo script abbia i permessi per scrivere sul file Warning: fopen(users.txt): failed to open stream: Permission denied in /var/www/php/register.php on line 14 Nella maggior parte dei sistemi gli script girano con l'utente del web server (di solito www-data) oppure con l'utente proprietario della directory che contiene lo script Permessi dei file sono triplette, primi 3 caratteri sono associati al proprietario dei file, es: rwx -> leggere, scrivere ed eseguire; la seconda trpletta (es: r-x) mi dice cosa possono fare gli utenti che appartengono allo stesso gruppo; e il terzo gruppo sono gli utenti del resto della macchina. OCCHIO ALLA CONCORRENZA! Se viene usato il web server online dove ci sono tanti utenti che ci accedono e se il file è sempre lo stesso bisogna gestire gli accesso concorrenti, quando aprite il file bisogna accedervi in modalità esclusiva, Lock per dire che se riesci ad aprire il file in scrittura per gli altri utenti viene accodato, quando si apre il Lock bisogna ricordarsi di lasciarlo. <?php $fp=fopen("users.txt","a"); $line = "............"; flock($fp,LOCK_EX); fwrite($fp,$line); flock($fp,LOCK_UN); fclose($fp); ?> LOCK_SH to acquire a shared lock (reader) LOCK_EX to acquire an exclusive lock (writer) LOCK_UN to release a lock (shared or exclusive) Vedi: http://php.net/manual/en/function.flock.php PHP7: INCLUDE/REQUIRE Nel caso di documenti in cui si ripetono più volte le stesse parti si possono usare le istruzioni include(), require(), require_once() Dei blocchi di codice che teniamo separati e li includiamo quando ci servono. <?php include(“comuni/header.php”); include(“comuni/navbar.php”); include(“comuni/leftmenu.php”); ?> page content here <?php include(“comuni/footer.php”); ?>
  18. Permette di progettare pagine web che si adattano a dispositivi di tipo diverso per dimensione dello schermo, risoluzione, orientamento. L'idea di sviluppare una sola applicazione che si adatti allo schermo di ogni dispositivo. Obiettivi minimi: adattare il layout al maggior numero di dispositivi adattare le dimensioni delle immagini (e in generedi tutti i contenuti a larghezza fissa) alla risoluzione e alle dimensioni dello schermo (grglie fluide, immagini flessibili) semplificare il layout degli elementi presenti sulla pagina per i dispositivi mobili con schermi piccoli nascondere gli elementi non essenziali sui dispositivi con schermi piccoli individuare e sfruttare, quando serve, funzionalità adatte al mobile (come la geolocalizzazione) CSS3 FLEXBOX Flexible Box Layout Module Semplifica la progettazione di layout flessibili senza richiedere l'uso di elementi di posizionamento Si deve definire una classe con proprietà .flexible-box { display: flex; } Si deve associare questa proprietà ad un contenitore (per esempio <div>) Tutti gli elementi all'interno del contenitore diventano "flessibili" Qui sotto vediamo un esempio di CSS con la proprietà flex: .flexible-box { display: flex; border: solid 2px #777777; flex-wrap: wrap; } .flexible-box > div { background-color: yellow; margin: 20px ; padding: 20px; font-size: 30px; border: solid 2px green; } e ora vediamo come implementarlo in HTML: <div class="flexible-box"> <div>1st element</div> <div>2nd element</div> <div>3rd element</div> .... </div> Per tutte le informazioni e approfondire i Flexbox vi rimandiamo a questa pagina css-tricks.com Non è l'unico modo per rappresentare le pagine responsive, prima del flexbox abbiamo i media query CSS3: MEDIA QUERY Una media query è costituita dalla regola @media che permette di specificare regole diverse per dispositivi diversi @media not|only mediatype and (media feature) { ... } @media screen { p.test { font-family:verdana, sans-serif; font-size:14px; } } @media print { p.test { font-family: times, serif; font-size: 10px } } Vengono introdotte le media features, dei meccanismi per riconoscere la risoluzione, l'orientamento dello schermo,... Permettono di associare il corretto foglio di stile ad un dispositivo con determinate caratteristiche @media screen and (width: 320px) and (orientation: portrait) and (resolution: 300dpi) { /* styles */ } @media only screen and (max-width:320px) { p {font-size: 2em; } } Sopra possiamo specificare un browser con il quale il cliente sta navigando ha uno schermo con ampiezza di 320px e un orientamento (portrait è verticale, e landscape è orizzontale) e la risoluzione del suo smartphone, possiamo applicare uno stile diverso. Mentre nel max-width 320px, ovvero in un browser con massimo 320px di larghezza possiamo applicare uno stile diverso. Si possono progettare file di stile per dispositivi diversi oppure mettere le media query in un unico foglio di stile. Esempio1: Possiamo creare un file foglio di stile diverso per ogni dispositivo con specifiche caratteristiche e aggiungere il meta link per ognuno in html: <link rel="stylesheet" media="only screen and (max-width: 480px)" href="smartphone.css" /> Esempio2: Un unico grande foglio di stile e andando a specificare ogni media query per ogni dispositivo che ci interessi e il suo orientamento come di seguito: /* Smartphones (portrait and landscape) ----------- */ @media only screen and (min-device-width : 320px) and (max-device-width : 480px) { /* Styles */ } /* Smartphones (landscape) ----------- */ @media only screen and (min-width : 321px) { /* Styles */ } /* Smartphones (portrait) ----------- */ @media only screen and (max-width : 320px) { /* Styles */ } Esistono anche le features max-width, min-width, max-height, min-height e molte altre... Vedi: https://www.w3.org/TR/css3-mediaqueries/ Vedi: http://www.w3schools.com/cssref/css3_pr_mediaquery.asp Vedi: https://developer.mozilla.org/en-US/docs/Web/CSS/@media Visualizzazione per iPhone e iPad iPhone e iPad tendono ad ignorare la risoluzione dello schermo e a zoomare le pagine Per forzare iPhone e iPad a rispettare la dimensione della viewport ci vuole un meta-tag all'interno del tag <head> <meta name = "viewport" content = "width=device-width" /> viewport: Area di visualizzazione del browser width: Larghezza della viewport device-width: Larghezza dello schermo del dispositivo BootStrap Bootstrap è il più famoso framework per HTML CSS e JS per sviluppare progetti nel web responsive e mobile. Esempio di CSS Responsive con display: flex e media query: html, body { font-family:Arial; margin:0; height: 100%; } h1 { margin:0; color:#900; } .centertext { text-align:center; } header { background-color:white; margin:0; width:100%; } footer { margin:0; width:100%; background-color:#600; color:white; height:30px; line-height:30px; font-size:0.8em; text-align:center; } aside { float:right; margin: 10px; width:45%; text-align:justify; } section { float:left; width:50%; } .responsive { max-width: 100%; height: auto; } .navigation { display: flex; flex-flow: row wrap; justify-content: flex-end; list-style: none; margin: 0; background: #600; } .navigation a { text-decoration: none; display: block; padding: 1em; color: white; } .navigation a:hover { background: #900; } @media all and (max-width: 800px) { .navigation { justify-content: space-around; } } @media all and (max-width: 600px) { .navigation { flex-flow: column wrap; padding: 0; } .navigation a { text-align: center; padding: 10px; } .navigation li:last-of-type a { border-bottom: none; } aside { width: 90%; margin: 10px; overflow: auto; } } .content { display: flex; flex-flow: row wrap; justify-content: flex-end; margin: 0; } @media all and (max-width: 800px) { .content { justify-content: space-around; } } @media all and (max-width: 600px) { .content { flex-flow: column wrap; padding: 0; Ecco il codice HTML per il foglio di stile css usato qui sopra: <!DOCTYPE html> <html> <head> <title>Il mio sito web personale</title> <link rel="stylesheet" type="text/css" href="stile.css"> </head> <body> <header> <h1 class="centertext">Le mie torte preferite</h1> </header> <nav> <ul class="navigation"> <li><a href="#">Chi sono</a> </li> <li><a href="#">Le mie foto </a> </li> <li><a href="#">Le mie torte</a> </li> <li><a href="#">Scrivimi</a></li> </ul> </nav> <div class="content"> <section class="centertext"> <figure> <img class="resposive" src="images/fruttibosco.png" alt="Frutti di bosco" width="400" height="315"> <br> <figurecaption>Torta ai frutti di bosco</figurecaption> </figure> </section> <aside> <h2>Preparazione</h2> <ol> <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</li> <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</li> </ol> </aside> </div> <footer class="clearfix">Copyright &copy; 2020-2021. Privacy.</footer> </body> </html>
  19. Seconda guida sul CSS3, nella prima abbiamo visto come usare i file con estensione .css e i selettori come classi e identificatori, ora ci addentriamo e andiamo a scoprire altro ancora. CSS3: Formattazione del testo Proprietà: color, tex-align, text-decoration, text-indent, e molte altre.. Non possiamo vedere tutte le proprietà, su W3SCHOOLS, trovate tutte le proprietà, ma sono molte. h1 { letter-spacing: 3px; color: green; text-align: center; text-decoration: overline; font-family: "Comic Sans MS"; } h2 { color: blue; text-align: right; text-decoration: overline; } Qui sopra abbiamo un esempio di alcune proprietà, per facilità di lettura si scrivono una per riga, ma nessuno vieta di scrivere tutto sulla stessa riga. CSS3: WEB FONT Grazie alla regola @font-face di CSS3 si possono definire nuovi nomi di font che usano famiglie di caratteri presi da server remoti @font-face { font-family:"nuovo-font"; src:url("nuovo-font.ttf"); /* <- file che definisce il nuovo tipo di carattere } Il file deve essere in remoto altrimenti non viene visualizzato poichè il browser e il computer dell'utente non riescono ad aprire il file del carattere. CSS3: text-shadow Per ottenere ombre, effetti neon, e 3D, ecc. si può usare la proprietà text-shadow che accetta un elenco di valori per specificare, offset-x, offset-y, blur-radius, color Vediamo ora alcuni esempi: CSS3: SFONDI La proprietà CSS background permette di gestire lo sfondo delle pagine visualizzate all'interno del browser, background-color, background-image, background-repeat, background-attachment, background-position Ecco un esempio di background: CSS3 introduce la possibilità di utilizzare più immagini di sfondo specificando i nomi dei file e i valori delle diverse proprietà separati da una virgola. CSS3: BOX MODEL Abbiamo già visto brevemente su HTML5, ora con i stili possiamo agire sulle proprietà. content: il contenuto vero e proprio del box padding: lascia uno spazio (trasparente) intorno al contenuto border: crea un bordo che circonda padding e contenuto margin: lascia uno spazio (trasparente) intorno al bordo border-radius: permette di definire bordi arrotondati box-shadow: permette di definire una o più ombre per i riquadri generati dagli elementi HTML Tutte le proprietà CSS viste fino ad ora (testo, sfondi, box-model) vanno usati con moderazione. CSS3: TRASFORMAZIONI CSS3 introduce funzioni per ridimensionare, ruotare, distorcere e traslare i vari elementi della pagina, introdurre transizioni e creare animazioni... scale(), rotate(), skew(), traslate() Le transizioni CSS3 permettono di controllare la velocità delle trasformazioni attraverso 4 proprietà: transition-property: specifica la proprietà CSS in cui applicare la trasformazione transition-duration transition-timing-function: velocità con cui viene eseguita l'animazione: easy, linear,.. transition-delay CSS3: POSIZIONAMENTO Possiamo attraverso i fogli di stile posizionare i nostri elementi dove vogliamo: block: in blocco uno sotto l'altro, ES: <div>,<p>,<h1> inline: in riga uno affianco all'altro, ES: <span>, <strong>, <em> La proprietà è display: block, display: inline, display: none La proprietà position permette di definire il posizionamento dei blocchi: static: default, segue il flusso della pagina, ignora top, left.. fixed: fisso, si spsota di top, left,.. rispetto all'angolo in alto/sx del browser e non scorre con il resto del documento. absolute: si sposta di top, left,.. rispetto al primo contenitore con posizionamento diverso da static, se esiste, oppure rispetto alla pagina. relative: si sposta di top, left,.. rispetto al posto che avrebbe occupato in assenza di posizionamento. La proprietà Z-index specifica la posizione di un elemento rispetto ad un altro, è molto utilizzata nello sviluppo dei vari layout, ad esempio quando occorre scrivere su di un’immagine oppure bisogna posizionare un elemento contenitore davanti o dietro ad un altro. z-index CSS valori possibili: valori numerici: valori positivi, negativi o il valore zero. auto: è quello di default. inherit: valore ereditato da un elemento padre. <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>Esempio proprietà z-index</title> <style> .immagine { width:500px; position: absolute; left: 0px; top: 0px; opacity:0.2; z-index: -1; } </style> </head> <body> <h1>Proprietà z-index CSS</h1> <img class="immagine" src="sito_div/img/time.jpg"> <div> Testo sull'immagine con z-index! </div> </body> </html> CSS3: FLOAT La proprietà float permette di spostare gli elementi in una pagina HTML senza usare tabelle, float: left, float: right, float: none Nota: spesso per riportare le cose a posto si usa clear: ... <style type=”text/css”> .imleft { float: left; margin: 15px 15px 5px 15px; border: solid 4px #bbb; } .imright { float: right; margin: 15px 15px 5px 15px; border: solid 4px #bbb; } </style> CSS3: TABLELESS LAYOUT Le proprietà position, float, clear applicate ai tag HTML permettono di realizzare layout senza tabelle Di solito si definiscono degli identificatori che si applicano ai tag <div> e <span> Un effetto simile si può ottenere definendo lo stile degli elementi semantici di HTML5 HTML4 HTML5 <div id="header"> <header> <div id="menu"> <nav> <div id="content"> <section> <div id="post"> <article> <div id="footer"> <footer> Vedi: http://www.w3schools.com/html/html5_migration.asp CSS3: funzioni “browser specific” Quando le nuove proprietà CSS3 non sono supportate, potrebbero esserci delle proprietà equivalenti che hanno un nome/valore “browser-specific” Chrome, Safari: -webkit- Firefox: -moz- Opera: -o- Explorer: -ms- Bisogna sempre guardare la documentazione https://developer.mozilla.org/en-US/docs/Web/CSS/Reference Esempio HTML5 con TAG SEMANTICI: <!DOCTYPE html> <html> <head> <title>Il mio sito web personale</title> <link rel="stylesheet" type="text/css" href="stile.css"> </head> <body> <header> <h1 class="centertext">Le mie torte preferite</h1> </header> <nav> <ul id="menu"> <li><a href="#">Chi sono</a> </li> <li><a href="#">Le mie foto </a> </li> <li><a href="#">Le mie torte</a> </li> <li><a href="#">Scrivimi</a></li> </ul> </nav> <section class="centertext"> <figure> <img src="images/fruttibosco.png" alt="Frutti di bosco" width="400" height="315"> <br> <figurecaption>Torta ai frutti di bosco</figurecaption> </figure> </section> <aside> <h2>Preparazione</h2> <ol> <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.</li> <li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud.</li> </ol> </aside> <footer>Copyright &copy; 2020-2021. Privacy.</footer> </body> </html> Esempio CSS3: html, body { font-family:Arial; margin:0; height: 100%; } h1 { margin:0; color:#900; } .centertext { text-align:center; } header { background-colora:white; margin:0; width:100%; } footer { margin:0; width:100%; background-color:#600; color:white; height:30px; line-height:30px; font-size:0.8em; text-align:center; position: absolute; bottom: 0; left: 0; } aside { float:right; width:45%; margin: 10px; text-align:justify; } section { float:left; width:50%; } #menu { list-style-type:none; margin:0; padding:0; height:30px; background-color:#600; font-family:Arial; } #menu li { float:right; height:30px; line-height:30px; } #menu li a { display:block; padding:0 20px; color:#FFF; text-decoration:none; } #menu li a:hover { background-color:#900; text-decoration:none; }
  20. Cosa sono i Fogli di Stile? I fogli di stile, CSS, servono per facilitare la creazione di pagine HTML con un aspetto uniforme, permettono di separare il contenuto di una documento dalla sua presentazione; possiamo "dimenticare" molti attributi HTML Permettono di modificare il look&feel di un documento in modo efficiente Lo stesso stile può essere applicato a più documenti Il sorgente HTML è più "pulito" e il download dei documenti è più veloce Si possono progettare pagine HTML per più dispositivi, formattando la pagina per le diverse risoluzioni dei browser. CSS3: REGOLE Un foglio di stile fornisce una collezione di regole che definiscono l'aspetto degli elementi di una pagina selector { property1 : value1; property1 : value1; ... } Bisogna creare una pagina non più html ma con estensione .css e qui possiamo mettere tutti i selettori che ci servono dentro le parentesi graffe. Le proprietà sono davvero tanti, dobbiamo solo capire come funzionano e capire il loro meccanismo. h1 { color:blue; font-size:12px; } Sopra abbiamo il selettore h1 che possiamo modificare con questo stile e le sue proprietà colore blu e il carattere di dimensione 12 px. CSS3: CLASSI "." Si definisce uno stile che si può applicare a più elementi nella stessa pagina, su tag diversi .important { color:blue; font-weight: bold; } Per applicare la classe sopra dobbiamo inserire la classe all'interno dei nostri tag nella pagina html: <p class="important">Questo è il secondo... </p> CSS3: ID "#" (identificatore) Si definisce uno stile che si può applicare ad un solo elemento nella pagina #superImportant { color: red; text-transform: uppercase; } Per applicare l'identificatore sopra dobbiamo inserirlo all'interno dei nostri tag nella pagina html: <p id="superImportant">Questo è il terzo... </p> CSS3: Pseudo Classi Distinguono gli elementi in base ad uno stato speciale a:link { color:white; text-decoration:none; } /* unvisited link */ a:visited { color:black; text-decoration:none; } /* visited link */ a:hover { color:red; text-decoration:none; } /* mouse over link */ div:hover { background-color:yellow; } Qui possiamo formattare i link ovvero i collegamenti nella nostra pagina, possiamo decidere link non ancora visitato, quando ci passiamo col mouse sopra e quando abbiamo già visitato il link. Selezionano una parte di un elemento, formattiamo ora il paragrafo: body { font-family:Arial, sans-serif; } p:first-line { color:blue; font-style:italic; } p:first-letter { color:green; font-size:50pt; font-style:italic; } li:first-child { color:red; } CSS3: Selettore di attributo Possiamo cambiare lo stile attraverso gli attributi [att...] [att^=val] /* attributi att che iniziano con val */ [att$=val] /* attributi att che finiscono con val */ [att*=val] /* attributi att il cui valore contiene val */ Esempio a[href*="mar"]{...} si applica ai link che contengono unige <a href="https://mario.it">Mario.it</a> <a href="https://libri.mario.it">Mario.it</a> CSS3: Combinare i selettori Se si vuole associare la stessa regola CSS a più selettori, si possono scrivere i selettori separati da una virgola ul.menu, a:link, p:first-child { ... } Lo spazio permette invece di creare una "discendenza" tra selettori, per es. ul.menu a:link permette di selezionare tutti i link (a:link) contenuti in un elenco <ul> associato alla classe menu Il cominatore '+' seleziona il primo elemento (fratello) che segue il primo elemento specificato ES: div + p prende il primo paragrafo <p> che segue immediatamente un elemento di tipo <div> Il combinatore '~' seleziona i nodi fratelli che seguono il primo elemento specificato il combinatore '>' seleziona i figli diretti del primo elemento ES: ul>li prende tutti gli elementi <li> dentro un <ul> CSS3: COME SI USANO Ci sono tre modi per associare uno stile ad un file HTML EXTERNAL <head> <link rel="stylesheet" type="text/css" href="mystyle.css" /> </head> INTERNAL <head> <style> /*regole di stile qui </style> </head> INLINE <h1 style="color:blue; margin-left:30px;"> ... </h1> Se si usano le stesse proprietà in stili diversi, come si risolvono i conflitti? Precedenza: LAST WRITE WINS, a cascata, vince l'ultimo ovvero Inline se esiste se no si passa a Internal e poi ad External. Browser default External Internal Inline Qui di seguito vediamo un foglio di stile .css di una pagina con input e vari selettori usati con identificatori e classi: html, body { font-family: Arial; margin: 0; color: white; } input[type=text], input[type=email], input[type=password] { border: 2px solid #8d99ae; border-radius: 10px; margin: 5px; padding: 10px; } .no-outline:focus { outline: none; } input[type=submit] { background-color: #ef233c; border: none; border-radius: 10px; color: white; cursor: pointer; font-weight: bold; margin: 8px 0; padding: 10px; } input[type=submit]:hover { background-color: #d90429; } #mydiv { background-color: #3d5a80; border-radius: 20px; border: 2px solid #8d99ae; padding: 20px; width: 30%; min-width: 270px; margin: auto; tex-align: center; } #myform { text-align: center; }
  21. HTML5 Parte 3 Guida Programmare passo per passo Questa è la lezione #3 dove parliamo di div e span. HTML5: DIV e SPAN Questi due tag ci permettono di inserire all'interno della pagina degli elementi, tramite i fogli di stile, possiamo decidere il rendering di questi elementi all'interno nella nostra pagina web. Ogni elemento HTML ha una visualizzazione standard che dipende dal tipo dell'elemento, gli elementi possono essere di tipo: block (visualizzati sempre su una nuova riga) esempi: <h1>, ..., <h6>, <p>, <form>, <div> inline (non iniziano su una nuova riga e occupano solo lo spazio necessario esempi: <img>, <a>, <span> Questa è una struttura molto importante per capire il comportamento HTML, il browser fa il rendering del documento, crea una struttura dati interna DOM, documento object model, un albero che ha tanti nodi quanti sono gli elementi della pagina, la radice è associata al tag html, al di sotto head e body che sono figli del nodo html. <!DOCTYPE html> <html> <head> <title>Titolo della pagina</title> </head> <body> <h1>Titolo principale</h1> <div>un nuovo blocco</div> <p><span>Primo paragrafo</span> <a href="first.html">Primo link</a></p> </body> </html> Nell'immagine di sotto, se introduciamo i tag <div> e <span>, il browser cambia la struttura dei blocchi della pagina, div che come vedete è un blocco, e span che rimane nella stessa riga del link href accanto. Si possono modificare tramite fogli di stile CSS e modificare complatemente l'albero per fare visualizzarli a piacimento. HTML: BOX MODEL Tutti i tag HTML definiscono dei blocchi e si può agire sul loro stile andando a modificarne opportune proprietà Prima del contenuto possiamo modificare il Padding, spazio che viene utilizzato tra il contenuto e il Bordo del blocco, e tramite il CSS possiamo modificare tutte queste proprietà, Border è il bordo del blocco anche questo modificabile a piacimento, e infine Margin, ovvero se vogliamo lasciare altro spazio tra il blocco e l'altro contenuto. HTML: TABLELESS LAYOUT Usati insieme alle classi e agli identificatori CSS, <div> e <pan> permettono di costruire layout di pagine HTML senza tabelle (tableless) che risultano accessbili anche a browser vocali HTML5: ELEMENTI SEMANTICI Un elemento semantico descrive anche il suo contenuto, <span>, <div> NON dicono nulla relativamente al proprio contenuto, <form>, <img>, <h1> "descrivono il proprio contenuto. Nelle versioni precedenti di HTML si usavano gli identificatori e e le classi CSS per definire le parti di una pagina web. Con l'html5 abbiamo questi nuovi tag, per costruire le pagine del nostro sito, <header> abbiamo il logo e altri pulsanti che vogliamo inserire, <nav> per il menu in alto, <section> una sezione particolare, <article> se abbiamo un articolo di blog o news, <aside> colonna verticale per articoli o advertising, <footer> per il menu infondo o il copyright. Agli elementi semantici non viene associata nessuna formattazione di default, usando i CSS è possibile modificare lo stile delle pagine web agendo sui tag semantici. HTML5 integrato con oggetti Javascript offre anche API per Geolocation, Canvas, Drag&Drop, Local Storage... Al giorno d'oggi è importante per i motori di ricerca, tramite crawler possono identificare le pagine che cambiano e migliorare il nostro SEO e SEM su Google o altri motori. I motori guardano il testo contenuto nella pagina e poi la struttura dei link di come le pagine sono collegate tra di loro. Per un Tutorial completo possiamo seguire la pagina ufficiale di W3SCHOOLS Qui di seguito possiamo vedere un esempio di una pagina HTML, dove abbiamo usato i Form per creare una pagina di registrazione. <!DOCTYPE html> <html lang="it"> <head> <title>Sign-up</title> <link rel="stylesheet" type="text/css" href="style.css"> <link rel="stylesheet" type="text/css" href="INSERISCI URL CSS AWESOME"> </head> <body> <br> <div id="mydiv"> <form id="myform" action="#" method="POST"> <i class="fas fa-file-signature"></i> <input type="text" class="no-outline" id="firstname" name="firstname" placeholder="Firstname"><br> <i class="fas fa-file-signature"></i> <input type="text" class="no-outline" id="lastname" name="lastname" placeholder="Lastname"><br> <i class="fas fa-at"></i> <input type="email" id="email" class="no-outline" name="email" placeholder="E-mail"><br> <i class="fas fa-key"></i> <input type="password" class="no-outline" id="pass" name="pass" placeholder="Password"><br> <i class="fas fa-key"></i> <input type="password" class="no-outline" id="confirm" name="confirm" placeholder="Confirm password"> <br> <input type="submit" value="Submit"> </form> </div> </body> </html>
  22. Perchè usare HTML5? HTML è un linguaggio di markup, usato in tutti i siti web per visualizzare testo formattato e multimedia. Questa guida continua la lezione 1 -> clicca qui se hai perso la lezione precedente. HTML5: LINK La struttura per creare i link, collegamenti ad altre pagine, è il seguente: <a href="URL"> link text </a> ES: <a href="http://www.google.it"> Google.it </a> URL= UNIFORM RESOURCE LOCATOR, può essere un indirizzo web complet (http://...) oppure può indicare un file sul file system dove risiede il file HTML con il link (nella Document Root!) PATH relativo se i file sono nella stessa cartella. Per esempio su Windows entrare in una Cartella e i file HTML nella stessa cartella, basta mettere l'indirizzo del file e non l'intero percorso della cartella (PATH). HTML: TABELLE Fino a qualche tempo fa il layout delle pagine HTML veniva realizzato mediante l'uso di tabelle più o meno sofisticate. All'interno delle celle di una tabella venivano inseriti gli elementi della pagine in modo da poterli disporre affiancati, o a cascata, o in un altro ordine. Oggi l'utilizzo delle tabelle si è ridotto notevolmente e per la creazione di layout si usano i tag <div> e <span> con opportunte regole di stile CSS.. L'uso delle tabelle HTML può ancora essere utile nel caso in cui si vogliano rappresentare dati tabellari, per esempio orari, dati numerici, previsioni meteo.. HTML: MODULI I form web (moduli) sono usati per ricevere i dati dagli utenti <form action="..." method="" name=""> elementi del form elementi del form elementi del form </form> action: - si deve specificare l'azione che viene eseguita quando si inviano i dati - di solito si scrive il nome di un programma sul server che si occupa della gestione dei dati inviati method: - GET (querystring i dati inviati sono visibili nella barra degli indirizzi sul browser, si usa per esempio nella ricerca di un testo) - POST (si usa quando i dati del form modificano lo stato sul server o si inviano informazioni sensibili, per esempio quando ci si registra ad un sito web) Il tag <input> permette di specificare gli elementi di un form Aspetto e comportamento dipendono dall'attributo type <input type="text"> <input type="radio"> <input type="checkbox"> <input type="password"> <input type="submit"> <input type="reset"> <input type="hidden"> <input type="file"> Per inviare correttamente i dati di un form ogni elemento deve avere un nome univoco, specificato con l'attributo name (con l'eccezione dell'elemento di tipo radio, che deve avere stesso nome perchè fa parte dello stesso blocco) <input type="text" name="cognome"> <input type="radio" name="studio">Licenza elementare <input type="radio" name="studio">Licenza media I dati inviati tramite form sono inseriti dall'utente oppure pre-impostati con l'attributo value <input type="radio" name="studio" value="elementare">Licenza elementare ora vediamo un esempio di un form completo: <form action="/action_page.php"> <label for="fname">First name:</label><br> <input type="text" id="fname" name="fname" value="John"><br> <label for="lname">Last name:</label><br> <input type="text" id="lname" name="lname" value="Doe"><br><br> <input type="submit" value="Submit"> </form> Potete provare i form direttamente nel sito di w3schools.com Con HTML5 sono stati introdotti nuovi valori dell'attributo type che permettono una migliore esperienza d'uso da parte dell'utente e facilitano i controlli dell'input da parte del programmatore, color, date, datetime, email, url, month, number, range, search, tel, time, week HTML5: MENU E' possibile inserire dei menu nei form usando i tag <select> ... </select> e <option> ... </option> <select> ha anche un attributo size per specificare quanti elementi del menu devono essere visibili; se non si specifica nulla, c'è un solo elemento visibile <form action=""> <select name="cars" seze="4"> <option value="volvo">Volvo</option> <option value="saab">Saab</option> <option value="fiat">Fiat</option> </select> </form> HTML5: COMMENTI TESTUALI Possono essere scritti all'interno del tag <textarea> ... <textarea> Per esempio quando abbiamo form dove chiede un commento oppure una recensione: <textarea rows="10" cols="20"> Inserisci un commento qui </textarea> HTML5: COMMENTI TESTUALI Editor di tipo textarea molto più completi e avanzati con il <textarea> come per esempio word detti editor WYSWYG. Si scarica la libreria, semplice script da integrare nel nostro file, e una volta aggiunto il tag <textarea> ci darà l'editor completo:
  23. Cos è HTML5? HTML, Hyper Text Markup Language, introdotto negli anni 90. Si è evoluto fino alla versione odierna la 5, codice che server per formattare un documento, poichè è formato da TAG quindi uno di apertura e uno di chiusura formattando all'interno il suo contenuto. Editor WYSIWYG, quello che vedi è quello che ottieni, come Office, poichè basta premere un tasto e vedi subito le modifiche. Editor di MARKUP come il nostro HTML5, cioè dei comandi che dicono come formattare il testo, costituito da due parti il contenuto vero e proprio e proprio le "istruzioni" che specificano come il contenuto deve essere rappresentato sul dispositivo (lo schermo di un pc, una stampante, un browser,..) In genere si racchiude il testo tra istruzioni chiamate tag (o etichette o codici). Gli iptertesti del web sono scritti usando il linguaggio HTML. HTML non è un linguaggio di programmazione! HTML è un linguaggio di markup permetti di descrivere la disposizione di tutti gli elementi di un documento visualizzato all'interno di un browser. I documenti HTML sono file in formato testo (ASCII) che si possono creare con editor di testo e hanno estensione .html. Esistono editor online per HTML che possono essere utili per imparare: su Google "html Editor", esempio codepen.io I browser leggono i documenti HTML in modo sequenziale e li visualizzano interpretando le specifiche di formattazione. HTML5: SINTASSI Un documento HTML inizia sempre con la dichiarazione del DOCTYPE che specifica la versione del linguaggio che viene usata, esistono diverse versioni di HTML: HTML 4.0 HTML 5.0 (standard dall'ottobre 2014) XHTML <nome comando> informazioni </nome comando> Dopo il DOCTYPE, si introduce il tag <html> che va chiuso con </html> al fondo del documento. HTML è case-insensitive e quindi <HTML>,<html>,<Html> sono tutti tag leciti. con l'introduzione di XHTML e con HTML5 si suggerisce di scrivere tutti i tag con caratteri minuscoli. < <!DOCTYPE html> <----- HTML5 <html> <head> <title>Document Title here</title> <meta name="keywords" content="keywords here" /> <meta name="author" content="name and surname here" /> ................ </head> <body> Content to be shown in the browser here ...... </body> </html> In questo sito (validator.w3.org) potete vedere se una pagina contiene errori. HTML5: DOCUMENTO HTML permette(va) di specificare come il cotenuto deve essere visualizzato, oggi si tente a separare il contenuto dalla sua presentazione. <body bgcolor="background color" background="file name" ... > I tag dentro il body sono informazioni di stile (CSS) e non si usa più, questa scelta è deprecata, tutte queste vanno fuori dal file nel foglio di stile. HTML: Codifica RGB Ogni colore può essere codificato con tre numeri compresi tra 0 e 255 che indicano le quantità di ROSSO, VERDE e BLU presenti nel colore stesso. Con questa codifica si possono rappresentare più di 16 milioni di colori. Per specificare i colori si possono usare: Parole chiave: white, black, green... Codifica esadecimale: #cc3300 Funzione rgb(): rgb(85,196,63) Funzione rgba() che ha un quarto parametro intero per specificare l'opacità (canale alpha) di un colore HTML5: TITOLI e PARAGRAFI Per i titoli si usa <h1> title level 1 </h1> <h2> title level 2 </h2> .... <h6> title level 6 </h6> Per i paragrafi si usa <p> text here </p> Potete fare prove e mettere mano sul sito w3schools.com/html/ <!DOCTYPE html> <----- HTML5 <html> <head> <title>Document Title here</title> </head> <body> <h1> My first Heading</h1> <p> My first paragraph.</p> </body> </html> HTML5: FORMATO e TESTO Queste parole si vedranno in grassetto: <b> bold text </b> <strong> bold text </strong> Questo tag serve per mettere parole in corsivo: <i> italic text </i> <em> italic text </em> HTML5: ALLINEAMENTO e LISTE Per formattare il documento centrato, a destra o sinistra, o giustificato si usano i seguenti tag, facendo parte sempre del paragrafo: <p align="center"> testo centrato </p> <p align="right"> testo tutto a destra </p> <p align="justify"> testo giustificato </p> <center> testo centrato </center> // DEPRECATO non si usa più In questa lista abbiamo gli elementi non ordinati, quindi col punto iniziale: <ul> <li> first element </li> <li> second element </li> </ul> Mentre in questa abbiamo gli elementi ordinati con i numeri: <ol> <li> first element </li> <li> second element </li> </ol> HTML5: IMMAGINI Per aggiungere un immagine si usa il tag img: <img src="image-name" alt="short text describing the image" // DEPRECATI: border="number" width="number" height="number" /> N.B.: l'immagine deve essere memorizzata su un file a parte Il tag alt è fondamentale per l'accessibilità delle pagine web! HTML5: MULTIMEDIA Le pagine web contengono risorse multimediali e con HTML5 si è cercato di standardizzare il loro utilizzo all'interno dei vari browser I formati audio e video sono tanti, HTML5 supporta: audio: MP3, WAV e Ogg video: MP4, WebM e Ogg <audio controls> <source src="audio.ogg" type="audio/ogg"> <source src="audio.mp3" type="audio/mpeg"> Il tuo browser non supporta il tag audio </audio> autoplay fa partire immediatamente l'audio loop riproduce continuamente il file audio <video width="320" height="240" controls> <source src="movie.mp4" type="video/ogg"> <source src="movie.ogv" type="video/ogv"> Il tuo browser non supporta il tag audio </video> autoplay fa partire automaticamente la riproduzione il tag <track> permette di associare sottotitoli al video E' possibile includere (iframe) in una pagina web uno o piu video che vengono visualizzati tramite Youtube. Copia il frammento di codice HTML di Youtube che si ottiene seguendo i link Share->Embed Incolla il frammento di codice HTML nel tuo file <iframe width="560" height="315" src="https://www.youtube.com/embed/4_Bjh-fLBVA" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> continua -> vedere lezione 2
×
×
  • Create New...

Important Information

Terms of Use Privacy Policy Guidelines We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.