Jump to content
  • Ultime Guide

    • 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] >>>  

    • 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]  
       

    • 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  
       

    • 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
       

    • 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)  
       

    • 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 ****  
       

    • 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
       
       
       
       
       
       
       
       
       

    • 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
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       

    • 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");  

    • 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; }  
       

    • 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}}  
       
       
       
       
       
       
       
       
       
       
       
       
       

    • 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.
       
      .

    • 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
       
       
       
       

    • 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
       
       
       

    • 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
       
       

    • 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!"; } ?>  
       

    • 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”); ?>  
       

    • 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>  
       

    • 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; }  
       

    • 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; }  
       

    • 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>  
       

    • 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:
       

       
       

    • 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

    • Questo tutorial spiegherà i primi passaggi di base che devi seguire dopo aver installato un sistema CentOS 7 minimale senza ambiente grafico per ottenere informazioni sul sistema installato, l'hardware sopra il quale esegue il sistema e configurare altre attività di sistema specifiche, come reti, privilegi di root, software, servizi e altro.
      Requisiti
      Installazione minima di CentOS 7
      Importante: gli utenti di RHEL 7 possono seguire questo articolo per eseguire una configurazione iniziale del server su RHEL 7.
      1. Aggiorna il sistema CentOS 7
      Il primo passo che devi eseguire su un nuovo sistema CentOS installato è assicurarti che il sistema sia aggiornato con le ultime patch di sicurezza del kernel e del sistema, repository software e pacchetti.
      Per aggiornare completamente un sistema CentOS 7, emettere i seguenti comandi con i privilegi di root.
      yum check-update yum upgrade Al termine del processo di aggiornamento, al fine di liberare spazio su disco è possibile rimuovere tutti i pacchetti scaricati che erano utilizzati nel processo di aggiornamento insieme a tutte le informazioni sui repository memorizzati eseguendo il comando seguente.
      yum clean all 2. Installa Utilità di sistema su CentOS 7
      I seguenti pacchetti di utilità possono rivelarsi utili per l'amministrazione del sistema giorno per giorno: nano (editor di testo per sostituire l'editor vi), wget, curl (utilità utilizzate principalmente per il download di pacchetti sulla rete) net-tools, lsof (utilità per la gestione rete locale) e bash-completion (completamento automatico della riga di comando).
      Installali tutti in un colpo solo eseguendo il comando seguente.
      yum install nano wget curl net-tools lsof bash-completion 3. Impostazione della rete in CentOS 7
      CentOS 7 ha una vasta gamma di strumenti che possono essere utilizzati per configurare e gestire la rete, dalla modifica manuale del file di configurazione di rete all'utilizzo di comandi come ip, ifconfig, nmtui, nmcli o route.
      L'utilità più semplice che un principiante può utilizzare per gestire e modificare le configurazioni di rete è la riga di comando grafica nmtui.
      Per modificare il nome host del sistema tramite l'utilità nmtui, eseguire il comando nmtui-hostname, impostare il nome host della macchina e premere OK per terminare, come illustrato nella schermata seguente.
      nmtui-hostname Per manipolare un'interfaccia di rete, eseguire il comando nmtui-edit, scegliere l'interfaccia che si desidera modificare e selezionare EDIT dal menu a destra, come mostrato nella schermata seguente.
      nmtui-edit Una volta entrati nell'interfaccia grafica fornita dall'utility nmtui, puoi configurare le impostazioni IP dell'interfaccia di rete come illustrato nella schermata seguente. Al termine, accedere a OK utilizzando il tasto [tab] per salvare la configurazione ed uscire.
       

      Per applicare la nuova configurazione dell'interfaccia di rete, eseguire il comando nmtui-connect, selezionare l'interfaccia che si desidera gestire e premere su Disattiva / Attiva opzione per disattivare e aumentare l'interfaccia con le impostazioni IP, come mostrato nelle schermate seguenti.
      nmtui-connect Per visualizzare le impostazioni dell'interfaccia di rete, è possibile controllare il contenuto del file di interfaccia oppure è possibile emettere i comandi seguenti.
      ifconfig enp0s3 ip a ping -c2 google.com Altre utilità utili che possono essere utilizzate per gestire la velocità, lo stato dei collegamenti o ottenere informazioni sulle interfacce di rete della macchina sono ethtool e mii-tool.
      ethtool enp0s3 mii-tool enp0s3 Un aspetto importante della rete della tua macchina è elencare tutte le prese di rete aperte per vedere quali programmi sono in ascolto su quali porte e qual è lo stato delle connessioni di rete stabilite.
      Per elencare tutti i server che hanno aperto socket TCP o UDP in stato di ascolto, immettere i seguenti comandi. Tuttavia, il server UDP non elenca alcuno stato socket a causa del fatto che UDP è un protocollo senza connessione che invia solo pacchetti sulla rete e non stabilisce connessioni.
      netstat -tulpn ss -tulpn lsof -i4 -6 4. Gestire i servizi in CentOS 7
      CentOS 7 gestisce i daemon o il servizio tramite l'utility systemctl. Per elencare tutti gli stati dei servizi, emettere il seguente comando.
      systemctl list-units Per verificare se un demone o un servizio è abilitato all'avvio automatico all'avvio del sistema, emettere il seguente comando.
      systemctl list-unit-files -t service Per elencare i vecchi servizi SysV presenti nel tuo sistema e disabilitarli, emetti i seguenti comandi chkconfig.
      chkconfig --list chkconfig service_name off 5. Disabilitare i servizi indesiderati in CentOS 7
      Dopo l'installazione di CentOS 7, si consiglia di elencare quali servizi sono in esecuzione nel sistema eseguendo i comandi precedenti e di disabilitarli e rimuoverli per ridurre i vettori di attacchi al proprio sistema.
      Ad esempio, il demone Postfix è installato e abilitato per impostazione predefinita in CentOS 7. Se il tuo sistema non richiede l'esecuzione di un server di posta, è meglio interrompere, disabilitare e rimuovere il servizio Postfix emettendo i comandi seguenti.
      systemctl stop postfix systemctl disable postfix yum remove postfix Oltre ai comandi netstat, ss, lsof o systemctl, puoi anche eseguire comandi ps, top o pstree per scoprire e identificare quali servizi indesiderati sono in esecuzione nel tuo sistema e disabilitarli o rimuoverli.
      Per impostazione predefinita, l'utilità pstree non è installata in CentOS 7. Per installarla, eseguire il comando seguente.
      yum install psmisc pstree -p 6. Abilita Firewall in CentOs 7
      Firewalld è la principale utility firewall con cui interagisce per gestire le regole di iptables.
      Per abilitare, avviare e verificare il firewall in CentOS 7, eseguire i seguenti comandi.
      systemctl enable firewalld systemctl start firewalld systemctl status firewalld Per aprire un servizio specifico alle connessioni in entrata, verificare innanzitutto se l'applicazione è già presente nelle regole firewalld, quindi aggiungere la regola per il servizio, come mostrato nell'esempio seguente che consente le connessioni in ingresso SSH. Utilizzare l'opzione --permanent per aggiungere la regola in modo permanente.
      firewall-cmd --add-service=[tab] #List services firewall-cmd --add-service=ssh firewall-cmd --add-service=ssh --permanent Nel caso in cui il servizio sia già definito nelle regole di firewalld, è possibile aggiungere manualmente la porta del servizio, come mostrato nell'esempio seguente.
      firewall-cmd --add-port=22/tcp --permanent firewall-cmd --reload #Apply the rule on-fly 7. Abilita le autorizzazioni Sudo per gli account utente
      Per concedere le autorizzazioni di root per un utente normale, creare innanzitutto l'utente immettendo il comando adduser, impostare la password per l'utente e concedere le autorizzazioni di root all'utente eseguendo il comando seguente che aggiunge il nuovo utente al gruppo di ruote amministrative.
      adduser finalalpha passwd finalalpha usermod -aG wheel finalalpha Per verificare se il nuovo utente ha i privilegi di root, accedi al sistema con le credenziali dell'utente ed esegui il comando yum con le autorizzazioni sudo, come mostrato nel seguente estratto.
      su - finalalpha sudo yum update Configurare l'autenticazione con chiave pubblica SSH su CentOS 7
      Per proteggere SSH il tuo server e impostare l'autenticazione con chiave pubblica per aumentare la sicurezza del tuo server con una chiave SSH privata per accedere, prima genera una coppia di chiavi SSH con un comando seguente.
      Non inserire una passphrase nel caso in cui desideri automatizzare la gestione del server tramite SSH.
      ssh-keygen -t RSA Dopo aver generato le coppie di chiavi SSH, copiare la chiave sul server a cui si desidera connettersi emettendo il comando seguente. Inizialmente, inserisci la password dell'utente SSH remoto per copiare la chiave pubblica.
      ssh-copy-id [email protected]_SERVER_IP Dopo che la chiave pubblica SSH è stata copiata sul server remoto, accedere al server SSH remoto con il comando seguente.
      ssh [email protected]_SERVER_IP Infine, per proteggere il server SSH, assicurati di non consentire l'accesso SSH remoto all'account root aprendo il file di configurazione SSH / etc / ssh / sshd_config con l'editor di testo come root e modificalo da Sì a No.
      PermitRootLogin no Per applicare l'impostazione è necessario riavviare il servizio SSH in modo che utilizzi la nuova configurazione.
      systemctl restart sshd È tutto! Queste sono solo alcune impostazioni e comandi di base che ogni amministratore di sistema deve conoscere e applicare su un nuovo sistema CentOS installato o per eseguire attività quotidiane sul sistema.

    • In questo tutorial, daremo uno sguardo ad alcune importanti attività da eseguire nel server per la configurazione iniziale del server e la protezione avanzata del server. Questi passaggi aumenteranno la sicurezza del server e l'usabilità. Eseguiremo una serie di attività come la creazione di un nuovo utente sudo, l'aggiornamento dei pacchetti, l'impostazione del fuso orario e la protezione del server SSH, ecc.
      Step 1: Log in via SSH
      Quando viene creato il server, nome utente, password e indirizzo IP predefiniti. Per il primo accesso, è necessario utilizzare tali credenziali per accedere al server. Se non hai familiarità con la modalità di connessione, consulta l'articolo "Come connettersi al server con SSH".
      Step 2: Change Logged in User Password
      Al primo accesso, è molto importante cambiare la password dell'utente corrente. Utilizzare il seguente comando per lo stesso.
      passwd Ti verrà chiesto di fornire la password esistente a meno che tu non abbia effettuato l'accesso come utente root.
      Step 3: Create a New Sudo User
      Se si è effettuato l'accesso come utente root, si consiglia di creare un utente sudo. Un utente Sudo è un utente con privilegi di superutente. In termini semplici, questo utente può eseguire comandi e attività amministrative come utente root.
      Per creare un nuovo utente, eseguire il comando seguente. Puoi sostituire il nome utente di esempio happysnel con qualsiasi cosa ti piaccia.
      sudo adduser NOMEUTENTE Nota: è possibile omettere l'utilizzo del comando sudo se si è effettuato l'accesso come utente root.
      Impostare una password per l'utente appena creato eseguendo il comando.
      sudo passwd NOMEUTENTE Aggiungi il tuo nuovo utente creato al gruppo wheel. Gli utenti nel gruppo wheel sono utenti sudo in CentOS 7.
      sudo usermod -aG wheel NOMEUTENTE Step 4: Logging in as the Newly Created User
      Esci dalla sessione terminale corrente eseguendo il comando di logout e accedi di nuovo usando ssh come nuovo utente.
      ssh [email protected] Step 5: Disable Root Login via SSH
      Trova l'impostazione corrente per l'accesso root tramite SSH eseguendo il comando seguente.
      sudo cat /etc/ssh/sshd_config | grep PermitRootLogin È possibile che venga visualizzato il seguente output.
      PermitRootLogin without-password # the setting of "PermitRootLogin without-password". Come nell'output sopra, possiamo vedere che, PermitRootLogin è impostato su senza password. Significa che l'autenticazione con password è disabilitata, tuttavia è abilitata l'autenticazione con chiave pubblica. Il che va bene nella maggior parte dei casi. Assicurarsi che non dovrebbe essere commentato o non dovrebbe essere impostato su Sì.
      Per disabilitare completamente l'accesso root, modificare il file eseguendo il comando seguente.
      sudo nano /etc/ssh/sshd_config E cambia la linea come segue.
      PermitRootLogin no Salvare il file e riavviare il server SSH eseguendo il comando seguente.
      sudo systemctl restart sshd Ora, se proverai ad accedere come utente root, non ti lascerà entrare.
      Step 6: Update Your Server
      È importante installare le ultime patch di sicurezza e gli aggiornamenti sul server. Eseguire il comando seguente per lo stesso.
      sudo yum -y update Nota: se viene visualizzato un messaggio che indica che è disponibile un pacchetto o file di aggiornamento, ma la versione installata viene modificata. Scegliere keep the local version currently installed 
      Step 7: Setting timezone
      You may want your server in the same timezone as you. Run the following command to get a list of available timezones.
      timedatectl list-timezones L'elenco dei fusi orari disponibili è disponibile anche qui.
      Una volta identificato il tuo fuso orario, impostalo utilizzando il seguente comando.
      sudo timedatectl set-timezone Europe/Amsterdam È possibile confermare il fuso orario eseguendo il comando seguente.
      timedatectl Step 8: Set Hostname
      Controlla il tuo nome host esistente eseguendo il comando seguente.
      hostnamectl Dovresti vedere un output simile.
      Static hostname: vps.snelexample.site Icon name: computer-vm Chassis: vm Machine ID: Boot ID: Virtualization: kvm Operating System: CentOS Linux 7 (Core) CPE OS Name: cpe:/o:centos:centos:7 Kernel: Linux 3.10.0-957.1.3.el7.x86_64 Architecture: x86-64 Per impostare un nome host, eseguire il comando seguente.
      sudo hostnamectl set-hostname host.snelexample.site Sostituisci host.snelexample.site con il tuo vero nome host. Preferibilmente, dovrebbe essere un nome di dominio completo (nome di dominio completo). Ma, se non si è sicuri di voler aggiungere un nome di dominio completo, funziona anche un'etichetta per identificare il server.
      Per risolvere il nome host nel tuo server locale, dovrai aggiungerlo al file / etc / hosts. Modifica il file hosts eseguendo il seguente comando.
      sudo nano /etc/hosts Se nano editor non è installato sul tuo server, installalo eseguendo il comando.
      sudo yum -y install nano Aggiungi il tuo nome host alla fine della riga che inizia con 127.0.0.1. Per esempio.
      127.0.0.1 localhost host.snelexample.site Step 9: Configure a Firewall
      Nella maggior parte dei casi, CentOS 7 viene fornito con Firewall abilitato per impostazione predefinita. È possibile verificare lo stato del firewall eseguendo il comando seguente.
      sudo firewall-cmd --state Dovrebbe essere running  se il firewall è già in esecuzione.
      Step 10: SSH Port Change (Optional)
      I bot dannosi su Internet puntano continuamente alla porta SSH predefinita 22. Puoi cambiarla in qualsiasi altra porta in modo che il tuo server non sia vittima di continui attacchi di robot sulla porta 22. Per cambiare la porta SSH, apri di nuovo il file di configurazione SSH eseguendo il comando seguente.
      sudo nano /etc/ssh/sshd_config Trova la linea che dice
      #Port 22 Rimuovi il commento e modificalo in qualsiasi porta che ti piace tra 1024 e 65535. Salvare il file ed uscire dall'editor.
      Ora, informa SELinux della porta SSH eseguendo il comando seguente.
      sudo yum -y install policycoreutils-python-utils sudo semanage port -a -t ssh_port_t -p tcp 2200 Aprire la porta 2200 dal firewall eseguendo i comandi.
      sudo firewall-cmd --permanent --add-port=2200/tcp sudo firewall-cmd --reload Ora, riavvia il server SSH eseguendo il comando seguente.
      sudo systemctl restart sshd Ora, se proverai ad accedere da un altro terminale senza specificare una porta, non ti lascerà entrare. Modifica il comando SSH per accedere per includere il numero di porta.
      ssh -p 2200 [email protected] Step 11: Reboot
      ora che abbiamo completato l'aggiornamento dei pacchetti e la configurazione del server. Riavvia il server in modo che, in caso di modifiche in sospeso, venga applicato.
      sudo reboot In questo tutorial, abbiamo imparato come impostare un utente sudo su istanze CentOS 7 appena create. Abbiamo configurato nome host, fuso orario e aggiornato i pacchetti. Abbiamo anche visto come impostare il fuso orario e il nome host, rafforzare il server SSH e aggiornare i pacchetti.

    • BIND può essere configurato come master o slave per servire la richiesta DNS per ogni zona. Quando BIND è configurato come slave, ottiene la copia dei dati di zona dal server master utilizzando il metodo di trasferimento di zona.
      Nel post precedente, avevamo configurato il server DNS su CentOS 7 che fungerà da sorgente per il server slave.
      Nome Dominio: finalalpha.net
      primary.finalalpha.net          192.168.1.10      Master DNS Server
      secondary.finalalpha.net     192.168.1.20      Slave DNS Server
      In questo, abbiamo due server chiamati primario e secondario.
      Il primario è già stato configurato come master per il dominio finalalpha.net.

      Ora configureremo secondario come server DNS slave per finalalpha.net.
      On Master Server
      Iniziamo ad inserire il Name server nel nostro etc/resolv.conf
      nameserver 192.168.1.10 Configurare BIND sul server principale per consentire il trasferimento di zona su un server secondario, modificare il file /etc/named.conf in primary.finalalpha.net.
      vi /etc/named.conf Aggiungi la seguente voce nel file. I server menzionati in allow-transfer saranno in grado di trasferire zone dal server master.
      options { allow-transfer { 192.168.1.20; }; also-notify { 192.168.1.20; }; } Ricordate di cambiare i permessi alla directory /var/named e a tutte le sottocartelle e file
      chmod 777 -Rvf /var/named/ Aggiungi le informazioni del tuo server DNS secondario nel file di ricerca diretta su primary.finalalpha.net.
      vi /var/named/finalalpha.net.db I record saranno come di seguito.
      @ IN SOA primary.finalalpha.net. www.finalalpha.net. ( 1002 ;Serial 3H ;Refresh 15M ;Retry 1W ;Expire 1D ;Minimum TTL ) ;Name Server Information @ IN NS primary.finalalpha.net. ;Secondary Name server @ IN NS secondary.finalalpha.net. ;IP address of Primary Name Server primary IN A 192.168.1.10 ;IP address of Secondary Name Server secondary IN A 192.168.1.20 ;Mail exchanger itzgeek.local. IN MX 10 mail.finalalpha.net. ;A - Record HostName To IP Address www IN A 192.168.1.100 mail IN A 192.168.1.150 ;CNAME record ftp IN CNAME www.finalalpha.net. Riavvia il servizio BIND. Aggiungi una regola di autorizzazione nel firewall per consentire le zone di trasferimento dal server principale.
      systemctl restart named firewall-cmd --permanent --add-port=53/tcp firewall-cmd --reload On Slave Server
      È il momento di aggiungere una dichiarazione della zona slave sul server secondario, assicurarsi di installare i seguenti pacchetti sul server secondario.
      yum -y install bind bind-utils Aggiungi il nameserver secondario su etc/resolv.conf
      nameserver 192.168.1.20 Modifica il file /etc/named.conf. Commenta la seguente riga per consentire a BIND di ascoltare su tutte le interfacce.
      // listen-on port 53 { 127.0.0.1; }; // listen-on-v6 port 53 { ::1; }; Aggiungi la tua rete nella seguente riga. Ho aggiunto 192.168.1.0/24 per consentire ai client della rete 192.168.1.0/24 di eseguire query sul DNS per il nome della traduzione IP.
      options { allow-query { localhost; 192.168.1.0/24; }; } Aggiungi la zona slave come di seguito.
      zone "itzgeek.local" IN { type slave; masters { 192.168.1.10; }; file "slaves/finalalpha.net.db"; }; zone "1.168.192.in-addr.arpa" IN { type slave; masters { 192.168.1.10; }; file "slaves/1.168.192.db"; }; finalalpha.net – Domain name
      slave – Secondary DNS
      finalalpha.net.db & 1.168.192.db – Slave forward & Reverse lookup file
      Riavviare il servizio BIND su secondario.finalalpha.net Aggiungi una regola di autorizzazione nel firewall per consentire ai client di connettersi al server DNS per la risoluzione dei nomi.
      firewall-cmd --permanent --add-port=53/udp firewall-cmd --reload Verifica la ricerca di www.finalalpha.net utilizzando secondario.finalalpha.net (192.168.1.20)
      dig @192.168.1.20 www.finalalpha.net Output
      ; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> @192.168.1.20 www.finalalpha.net ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5314 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;www.finalalpha.net. IN A ;; ANSWER SECTION: www.finalalpha.net. 604800 IN A 192.168.1.100 ;; AUTHORITY SECTION: finalalpha.net. 604800 IN NS secondary.finalalpha.net. finalalpha.net. 604800 IN NS primary.finalalpha.net. ;; ADDITIONAL SECTION: primary.finalalpha.net. 604800 IN A 192.168.1.10 secondary.finalalpha.net. 604800 IN A 192.168.1.20 ;; Query time: 0 msec ;; SERVER: 192.168.1.20#53(192.168.1.20) ;; WHEN: Wed Jul 17 21:53:45 IST 2019 ;; MSG SIZE rcvd: 140 Record Update
      Ogni volta che si modifica un record DNS sul server principale, non dimenticare di modificare il numero seriale nel file della zona ed eseguire il comando seguente sul server principale per ricaricare la zona.

      Cambia finalalpha.net e 1.168.192.in-addr.arpa con i nomi delle tue zone.
      ### Forward Zone ### rndc reload finalalpha.net ### Reverse Zone ### rndc reload 1.168.192.in-addr.arpa  

    • Il Domain Name System (DNS) è un sistema di denominazione distribuito gerarchico per computer, servizi o qualsiasi risorsa connessa a Internet o a una rete privata. Associa varie informazioni ai nomi di dominio assegnati a ciascuna delle entità partecipanti.
      Soprattutto, traduce i nomi di dominio significativi per l'uomo negli identificatori numerici associati alle apparecchiature di rete allo scopo di individuare e indirizzare questi dispositivi in tutto il mondo.
      Questa guida ti aiuterà a configurare il server DNS su CentOS 7 / RHEL 7. Server Name: finalalpha.net
      IP Address: 192.168.0.10
      Install DNS (BIND) BIND sta per Berkeley Internet Name Domain, un software che consente di eseguire la conversione da nome a IP.   yum -y install bind bind-utils Configure DNS (BIND)
      Per impostazione predefinita, BIND è in ascolto sull'host locale. Quindi, configureremo il server DNS per l'ascolto sull'indirizzo IP del sistema per consentire ai client di raggiungere il server DNS per la risoluzione dei nomi di dominio.
      vi /etc/named.conf Configura BIND per l'ascolto su tutti gli indirizzi IP.
      // listen-on port 53 { 127.0.0.1; }; // listen-on-v6 port 53 { ::1; }; Configurare BIND per ascoltare un determinato indirizzo IP.
      listen-on port 53 { 127.0.0.1; 192.168.0.10; }; Aggiungi la tua rete nella seguente riga. Questa impostazione consentirà ai client della rete menzionata di eseguire query sul DNS per la traduzione da nome a ip.
      Ho aggiunto 192.168.0.0/24 per questa demo.
      allow-query { localhost; 192.168.0.0/24; }; Create Zones
      vi /etc/named.conf Forward Zone
      La seguente zona è la voce della zona diretta per il dominio finalalpha.net.
      zone "finalalpha.net" IN { type master; file "/var/named/finalalpha.net.db"; allow-update { none; }; }; itzgeek.local – Domain name
      master – Primary DNS
      finalalpha.net.db – Forward lookup file
      allow-update – Since this is the primary DNS, it should be none
      Reverse Zone
      La seguente zona è la voce della zona inversa.
      zone "0.168.192.in-addr.arpa" IN { type master; file "/var/named/192.168.0.db"; allow-update { none; }; }; 0.168.192.in-addr.arpa – Reverse lookup name
      master – Primary DNS
      192.168.0.db – Reverse lookup file
      allow-update – Since this is the primary DNS, it should be none
      Create Zone Files
      Per impostazione predefinita, i file di ricerca della zona sono collocati nella directory /var/named. Creare un file di zona chiamato finalalpha.net.db per la ricerca diretta nella directory /var/named. Tutti i nomi di dominio dovrebbero terminare con un punto (.).
      vi /var/named/finalalpha.net.db Esistono alcune parole chiave speciali per i file di zona
      A – A record
      NS – Name Server
      MX – Mail for Exchange
      CNAME – Canonical Name
      @ IN SOA ns1.finalalpha.net. www.finalalpha.net. ( 1001 ;Serial 3H ;Refresh 15M ;Retry 1W ;Expire 1D ;Minimum TTL ) ;Name Server Information @ IN NS ns1.finalalpha.net. ;IP address of Name Server ns1 IN A 192.168.0.10 ;Mail exchanger itzgeek.local. IN MX 10 mail.finalalpha.net. ;A - Record HostName To IP Address www IN A 192.168.0.100 mail IN A 192.168.0.150 ;CNAME record ftp IN CNAME www.finalalpha.net. Ogni volta che aggiorni il file di ricerca della zona, devi cambiare / incrementare il seriale come 1002; Serial.
      Creare un file di zona chiamato 192.168.0.db per la zona inversa nella directory / var / named.
      vi /var/named/192.168.0.db Crea un puntatore inverso per le voci della zona diretta che abbiamo creato in precedenza.
      PTR – Pointer
      SOA – Start of Authority
      @ IN SOA ns1.finalalpha.net. www.finalalpha.net. ( 1001 ;Serial 3H ;Refresh 15M ;Retry 1W ;Expire 1D ;Minimum TTL ) ;Name Server Information @ IN NS ns1.finalalpha.net. ;Reverse lookup for Name Server 10 IN PTR ns1.finalalpha.net. ;PTR Record IP address to HostName 100 IN PTR www.finalalpha.net. 150 IN PTR mail.finalalpha.net. Ogni volta che aggiorni il file di ricerca della zona, devi cambiare / incrementare il seriale come 1002; Serial.
      Dopo aver creato i file di zona, riavviare il servizio di bind. Abilitalo all'avvio del sistema.
      systemctl restart named systemctl enable named Firewall
      Aggiungi una regola di autorizzazione nel firewall per consentire ai client di connettersi al server DNS per la risoluzione dei nomi.
      firewall-cmd --permanent --add-port=53/udp firewall-cmd --reload Verify Zones
      Visita qualsiasi macchina client e aggiungi un indirizzo IP del server DNS in /etc/resolv.conf.
      nameserver 192.168.0.10 Se Network Manager gestisce la rete, inserire la seguente voce nel file /etc/sysconfig/network-scripts/ifcfg-eXX
      DNS1=192.168.0.10 Riavvia il servizio di rete.
      systemctl restart NetworkManager Utilizzare il comando seguente per verificare la ricerca diretta.
      dig www.finalalpha.net Output: il server DNS dovrebbe fornire 192.168.0.100 come ip per www.finalalpha.net.
      ; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> www.itzgeek.local ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35563 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;www.itzgeek.local. IN A ;; ANSWER SECTION: www.itzgeek.local. 86400 IN A 192.168.0.100 ;; AUTHORITY SECTION: itzgeek.local. 86400 IN NS primary.itzgeek.local. ;; ADDITIONAL SECTION: ns1.itzgeek.local. 86400 IN A 192.168.0.10 ;; Query time: 0 msec ;; SERVER: 192.168.0.10#53(192.168.0.10) ;; WHEN: Wed Jul 03 02:00:40 EDT 2019 ;; MSG SIZE rcvd: 100 Conferma la ricerca inversa.
      dig -x 192.168.0.100 Output: il server DNS fornisce www.itzgeek.local come nome per 192.168.0.100.
      ; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> -x 192.168.0.100 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4807 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;100.0.168.192.in-addr.arpa. IN PTR ;; ANSWER SECTION: 100.0.168.192.in-addr.arpa. 86400 IN PTR www.itzgeek.local. ;; AUTHORITY SECTION: 0.168.192.in-addr.arpa. 86400 IN NS ns1.itzgeek.local. ;; ADDITIONAL SECTION: ns1.itzgeek.local. 86400 IN A 192.168.0.10 ;; Query time: 0 msec ;; SERVER: 192.168.0.10#53(192.168.0.10) ;; WHEN: Wed Jul 03 02:02:47 EDT 2019 ;; MSG SIZE rcvd: 124 È ora confermato che le ricerche sia in avanti che indietro stanno funzionando bene.
       

×
×
  • 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.