Contacte

Salutări, dragă prietenă! Program de afiliere Php de succes slab

Mecanismul standard pentru stocarea datelor sesiunii utilizatorului în php este stocarea în fișiere. Cu toate acestea, atunci când o aplicație rulează pe mai multe servere pentru echilibrarea încărcării, devine necesar să stocați datele sesiunii în stocarea disponibilă pentru fiecare server de aplicații. În acest caz, pentru stocarea sesiunilor, Redis.

Cea mai populară soluție este extensia phpredis. Este suficient să instalați extensia și să configurați php.ini, iar sesiunile vor fi salvate automat în Redis fără a modifica codul aplicației.

Cu toate acestea, această soluție are un dezavantaj - nu există blocare de sesiune.

Când utilizați mecanismul standard pentru stocarea sesiunilor în fișiere, o sesiune deschisă blochează fișierul până când este închis. Cu acces simultan multiplu la sesiune, noile solicitări vor aștepta până când cea anterioară finalizează sesiunea. Cu toate acestea, nu există un astfel de mecanism de blocare atunci când se utilizează phpredis. Cu mai multe cereri asincrone, o cursă are loc în același timp, iar unele date scrise în sesiune pot fi pierdute.

Este ușor de verificat. Trimitem asincron 100 de cereri către server, fiecare dintre ele scriindu-și propriul parametru în sesiune, apoi numărăm numărul de parametri din sesiune.

Script de testare

"; pauză;)


Ca rezultat, obținem că nu există 100 de parametri în sesiune, ci 60-80. Am pierdut restul datelor.
În aplicațiile reale, desigur, nu vor exista 100 de cereri simultane, dar practica arată că, chiar și cu două cereri simultane asincrone, datele scrise de una dintre cereri sunt destul de des suprascrise de cealaltă. Astfel, utilizarea extensiei phpredis pentru stocarea sesiunilor este nesigură și poate duce la pierderea datelor.

Ca una dintre opțiunile pentru rezolvarea problemei - dumneavoastră SessionHandler care acceptă blocarea.

Implementare

Pentru a bloca o sesiune, setați valoarea cheii de blocare la o valoare generată aleatoriu (bazată pe uniqid). Valoarea trebuie să fie unică, astfel încât orice solicitare paralelă să nu poată fi accesată.

Funcția protejată lockSession ($ sessionId) ($ încercări = (1000000 * $ this-> lockMaxWait) / $ this-> spinLockWait; $ this-> token = uniqid (); $ this->< $attempts; ++$i) { $success = $this->redis-> set ($ this-> getRedisKey ($ this-> lockKey), $ this-> token, ["NX",]); if ($ succes) ($ this-> locked = true; return true;) usleep ($ this-> spinLockWait); ) returnează fals; )
Valoarea este setată cu steagul NX, adică instalarea are loc numai dacă nu există o astfel de cheie. Dacă există o astfel de cheie, încercăm din nou după un timp.

Puteți utiliza, de asemenea, durata de viață limitată a cheii din ridiche, cu toate acestea, timpul de rulare al scriptului poate fi modificat după ce cheia este instalată, iar procesul paralel va putea accesa sesiunea înainte de a termina de lucrat cu ea în actualul scenariu. Când scriptul se termină, cheia este ștearsă în orice caz.

Când deblocați o sesiune la sfârșitul scriptului, utilizați Lua-scenariu:

Funcția privată unlockSession () ($ script =<<redis-> eval ($ script, array ($ this-> getRedisKey ($ this-> lockKey), $ this-> token), 1); $ this-> locked = false; $ this-> token = nul; )
Folosiți comanda DEL este imposibil, deoarece poate fi folosit pentru a șterge o cheie instalată de un alt script. Același scenariu garantează ștergerea numai dacă cheia de blocare corespunde unei valori unice setate de scriptul curent.

Codul clasei complet

clasa RedisSessionHandler implementează \ SessionHandlerInterface (protected $ redis; protected $ ttl; protected $ prefix; protected $ locked; private $ lockKey; private $ token; private $ spinLockWait; private $ lockMaxWait; funcție publică __construct (\ Redis $ redis, $ prefix = "PHPREDIS_SESSION:", $ spinLockWait = 200000) ($ this-> redis = $ redis; $ this-> ttl = ini_get ("gc_maxlifetime"); $ iniMaxExecutionTime = ini_get ("max_execution_time"); $ this-> lockMaxWait = $ iniMaxExecutionTime? $ iniMaxExecutionTime * 0.7: 20; $ this-> prefix = $ prefix; $ this-> locked = false; $ this-> lockKey = null; $ this-> spinLockWait = $ spinLockWait;) funcție publică deschisă ($ savePath , $ sessionName) (return true;) funcție protejată lockSession ($ sessionId) ($ încercări = (1000000 * $ this-> lockMaxWait) / $ this-> spinLockWait; $ this-> token = uniqid (); $ this-> lockKey = $ sessionId. ".lock"; for ($ i = 0; $ i< $attempts; ++$i) { $success = $this->redis-> set ($ this-> getRedisKey ($ this-> lockKey), $ this-> token, ["NX",]); if ($ succes) ($ this-> locked = true; return true;) usleep ($ this-> spinLockWait); ) returnează fals; ) funcție privată unlockSession () ($ script =<<redis-> eval ($ script, array ($ this-> getRedisKey ($ this-> lockKey), $ this-> token), 1); $ this-> locked = false; $ this-> token = nul; ) funcție publică close () (if ($ this-> locked) ($ this-> unlockSession ();) return true;) funcție publică read ($ sessionId) (if (! $ this-> locked) (if (! $ this-> lockSession ($ sessionId)) (return false;)) return $ this-> redis-> get ($ this-> getRedisKey ($ sessionId)) ?: "";) funcție publică write ($ sessionId, $ date) (if ($ this-> ttl> 0) ($ this-> redis-> setex ($ this-> getRedisKey ($ sessionId), $ this-> ttl, $ data);) else ($ this-> redis-> set ($ this-> getRedisKey ($ sessionId), $ data);) return true;) funcție publică destroy ($ sessionId) ($ this-> redis-> del ($ this-> getRedisKey ($ sessionId) ); $ this-> close (); return true;) funcție publică gc ($ durata de viață) (return true;) funcție publică setTtl ($ ttl) ($ this-> ttl = $ ttl;) funcție publică getLockMaxWait () ( returnează $ this-> lockMaxWait;) funcție publică setLockMaxWait ($ lockMaxWait) ($ this-> lockMaxWait = $ lockMaxWait;) funcție protejată getRedisKey ($ key) (if (goal ($ this-> prefix)) (return $ key; ) întoarcere $ this-> prefix. $ cheie; ) funcție publică __destruct () ($ this-> close ();))

Conexiune

$ redis = Redis nou (); if ($ redis-> connect ("11.111.111.11", 6379) && $ redis-> select (0)) ($ handler = new \ suffi \ RedisSessionHandler \ RedisSessionHandler ($ redis); session_set_save_handler ($ handler);) session_start ();

Rezultat

După conectarea noastră SessionHandler scriptul nostru de testare arată cu încredere 100 de parametri pe sesiune. În același timp, în ciuda blocării, timpul total de procesare a 100 de cereri a crescut nesemnificativ. În practica reală, nu va exista un astfel de număr de cereri simultane. Cu toate acestea, timpul de rulare al scriptului este de obicei mai semnificativ și pot exista timpi de așteptare vizibili pentru solicitări simultane. Prin urmare, trebuie să vă gândiți la reducerea timpului petrecut lucrând cu sesiunea de script (apelare session_start () numai atunci când este necesar să lucrați cu sesiunea și session_write_close () când termini să lucrezi cu el)

Face o cerere către server fără a reîncărca pagina. Aceasta este o metodă de nivel scăzut, cu multă personalizare. Este în centrul tuturor celorlalte metode ajax. Are două cazuri de utilizare:

url- adresa cererii.
setări- în acest parametru puteți seta setările pentru această solicitare. Specificat folosind un obiect în format (nume: valoare, nume: valoare ...). Niciuna dintre setări nu este necesară. Puteți seta setările implicite utilizând metoda $ .ajaxSetup ().

Lista de setări

↓ nume: tip (Mod implicit)

Când se face o cerere, anteturile specifică tipurile de conținut valide așteptate de la server. Valorile acestor tipuri vor fi preluate din parametrul acceptă.

În mod implicit, toate cererile fără reîncărcarea paginii au loc asincron (adică, după trimiterea unei cereri către server, pagina nu își oprește activitatea în timp ce așteaptă un răspuns). Dacă aveți nevoie de execuție de interogare sincronă, setați parametrul la fals. Solicitările între domenii și „jsonp” nu pot rula sincron.

Vă rugăm să rețineți că executarea cererilor în modul sincron poate duce la blocarea paginilor până la finalizarea completă a cererii.

Acest câmp conține o funcție care va fi apelată chiar înainte de a trimite cererea ajax către server. O astfel de funcție poate fi utilă pentru modificarea unui obiect jqXHR (în versiuni anterioare biblioteci (până la 1,5), se folosește XMLHttpRequest în locul jqXHR). De exemplu, puteți modifica / specifica antetele necesare etc. Object-jqXHR va fi transmis funcției ca prim argument. Al doilea argument este setările cererii.

În acest câmp pot fi specificate anteturi suplimentare de solicitare (antet). Aceste modificări vor fi implementate înainte de apelul către beforeSend, în care se pot face modificările finale ale antetului.

Când această setare este setată la adevărat, solicitarea va fi executată cu starea „reușită” numai dacă răspunsul de la server diferă de răspunsul anterior. jQuery verifică acest lucru făcând referire la antetul Last-Modified. De la jQuery-1.4, pe lângă Last-Modified, este verificat și „etag” (ambele sunt furnizate de server și sunt necesare pentru a notifica browserul că datele solicitate de pe server nu s-au modificat de la solicitarea anterioară).

Vă permite să setați starea sursei paginii la local (ca și cum ar folosi protocolul de fișier), chiar dacă jQuery a recunoscut-o diferit. Biblioteca decide ca pagina să fie lansată local în cazul următoarelor protocoale: fișier, extensie * și widget.

Se recomandă setarea valorii parametrului esteLocal global - folosind funcția $ .ajaxSetup (), nu în setările cererilor individuale ajax.

Definește numele parametrului, care este adăugat la adresa URL în timpul unei solicitări JSONP (în mod implicit, se folosește „callback” - „httr: //siteName.ru? Callback = ...”).

Din moment ce jQuery-1.5, specificarea false în acest parametru va împiedica adăugarea adresei URL parametru suplimentar... În acest caz, trebuie să setați în mod explicit valoarea proprietății jsonpCallback. De exemplu, astfel: (jsonp: false, jsonpCallback: "callbackName").

Definește numele funcției care va fi apelată atunci când serverul răspunde la o solicitare jsonp. În mod implicit, jQuery generează un nume arbitrar pentru această funcție, care este opțiunea preferată pentru a face biblioteca să funcționeze mai ușor. Unul dintre motivele pentru care ar trebui să specificați propria funcție pentru gestionarea solicitărilor jsonp este îmbunătățirea memorării în cache a solicitărilor GET.

De la jQuery-1.5, puteți specifica o funcție în acest parametru pentru a gestiona singur răspunsul serverului. În acest caz, funcția specificată trebuie să returneze datele primite de la server (în funcția specificată, acestea vor fi disponibile în primul parametru).

În mod implicit, toate datele transmise către server sunt pre-convertite într-un șir (format URL: fName1 = value1 & fName2 = value2 & ...) corespunzător „application / x-www-form-urlencoded”. Dacă trebuie să trimiteți date care nu pot fi procesate în acest fel (de exemplu, un document DOM), atunci ar trebui să dezactivați opțiunea processData.

Acest parametru este utilizat pentru cererile cross-domain ajax de tip GET, dataType poate fi „jsonp” sau „script”. Determină codificarea în care va fi executată cererea pe mai multe domenii. Acest lucru este necesar dacă serverul de pe un domeniu străin folosește o codificare diferită de codificarea de pe serverul de domeniu de acasă.

(Această setare a fost introdusă în jQuery-1.5) un set de perechi în care codurile de execuție ale cererii sunt mapate la funcțiile care vor fi apelate în acest caz. De exemplu, pentru un cod 404 (paginile nu există), puteți afișa un mesaj pe ecran:

$ .ajax ((statusCode: (404: function () (alert ( "Pagina nu a fost gasita") ; } } } ) ;

Funcțiile care răspund la coduri pentru executarea cu succes a unei cereri vor primi aceleași argumente ca funcțiile care gestionează executarea cu succes a unei cereri (specificate în parametrul de succes), iar funcțiile care răspund la codurile de eroare vor fi aceleași ca și pentru funcțiile de eroare.

Funcția care va fi apelată în cazul finalizării cu succes a cererii către server. Trei parametri îi vor fi trecuți: datele trimise de server și deja preprocesate (care diferă pentru tipul de date diferite). Al doilea parametru este un șir cu starea de execuție. Al treilea parametru conține obiectul jqXHR (în versiunile anterioare ale bibliotecii (până la 1.5), XMLHttpRequest este utilizat în loc de jqXHR). Deoarece jQuery-1.5, în loc de o singură funcție, acest parametru poate lua o serie de funcții.

Este timpul să așteptați un răspuns de la server. Setat în milisecunde. Dacă acest timp este depășit, solicitarea va fi completată cu o eroare și va apărea un eveniment de eroare (a se vedea descrierea de mai sus), care va avea starea „timeout”.

Timpul este numărat din momentul în care este apelată funcția $ .ajax. Se poate întâmpla ca în acest moment să fie lansate alte câteva solicitări și browserul să amâne executarea cererii actuale. În acest caz pauză poate completa, deși, de fapt, solicitarea nici măcar nu a fost încă lansată.

În jQuery-1.4 și versiuni anterioare, când expiră expirarea, obiectul XMLHttpRequest va intra într-o stare de eroare și accesul la câmpurile sale poate genera o excepție. ÎN Firefox 3.0+ cererile de script și JSONP nu vor fi întrerupte când expiră. Acestea vor fi finalizate chiar și după expirarea acestui timp.

O funcție care va oferi un obiect XMLHttpRequest. În mod implicit, pentru browserele IE acest obiect este un ActiveXObject, altfel este XMLHttpRequest. Cu acest parametru, puteți încorpora propria versiune a acestui obiect.

(Această setare a fost introdusă în jQuery-1.5.1) Un set de perechi (nume: valoare) pentru schimbarea / adăugarea valorilor câmpurilor corespunzătoare ale obiectului XMLHttpRequest. De exemplu, puteți seta proprietatea withCredentials la true atunci când faceți o cerere între domenii:

$ .ajax ((url: a_cross_domain_url, xhrFields: (withCredentials: true)));

ÎN jQuery-1.5 proprietatea withCredentials nu este acceptată de XMLHttpRequest nativ și acest câmp va fi ignorat într-o cerere între domenii. În toate versiunile ulterioare ale bibliotecii, acest lucru a fost remediat.

Manipulatori de evenimente

Setările beforeSend, error, dataFilter, succes și complete (descrise în secțiunea anterioară) vă permit să setați gestionare de evenimente care apar în puncte specifice în execuția fiecărei cereri ajax.

înainte de Trimitere apare chiar înainte ca solicitarea să fie trimisă la server. eroare apare dacă solicitarea eșuează. dataFilter apare atunci când datele sosesc de la server. Permite procesarea datelor brute trimise de server. succes apare dacă solicitarea se finalizează cu succes. complet apare la orice finalizare a cererii.

Exemplu utilizare simplă... Să afișăm un mesaj dacă solicitarea are succes:

$ .ajax ((url: "ajax / test.html", success: function () (alert ("Încărcarea a fost efectuată.");)));

Începând cu jQuery-1.5, metoda $ .ajax () returnează un obiect jqXHR care implementează interfața amânată, printre altele, permițându-vă să definiți handler-uri de execuție suplimentare. În plus față de metodele standard amânate .done (), .fail () și .then (), pe care le puteți utiliza pentru a seta handlerele, jqXHR implementează .success (), .error () și.complete (). Acest lucru se face pentru a se potrivi cu numele familiare ale metodelor utilizate pentru a configura handlerele pentru executarea cererilor ajax. Cu toate acestea, începând cu jQuery-1.8 aceste trei metode vor deveni nedorit pentru utilizare.

Unele tipuri de solicitări, cum ar fi cererile GET jsonp sau cross-domain, nu acceptă obiecte XMLHttpRequest. În acest caz, trecut către XMLHttpRequest și handlerele textStatus vor conține valoarea nedefinită.

În interiorul handlerelor, această variabilă va conține valoarea parametrului context... În cazul în care nu a fost setat, acesta va conține obiectul de setări.

Parametru DataType

Funcția $ .ajax () află despre tipul de date trimise de server de la server însuși (prin intermediul MIME). În plus, este posibil să indicați personal (să clarificați) modul în care aceste date ar trebui interpretate. Acest lucru se face folosind parametrul dataType. Valorile posibile pentru acest parametru:

„xml” - documentul XML rezultat va fi disponibil sub formă de text. Poți lucra cu el mijloace standard jQuery (la fel ca în cazul documentului html). „html” - html rezultat va fi disponibil sub formă de text. Dacă conține scripturi în etichete



Acest exemplu utilizând metoda jQuery .sarcină () când facem clic pe un element

Ți-a plăcut articolul? Împărtășește-l