Help! HTML

Stiu cum functioneaza, am scris ceva Html de-a lungul vremii, important e sa fie in stare sa il mentina cineva si optiunile nu sunt prea vesele. De-aia intrebam de variante cat mai simple.
 
A mai trecut ceva timp, au mai aparut intrebari :smile:

Intrebarea 1
Ma gandesc, initial academic ca apoi sa se si intample, care e cea mai buna varianta pentru un site foarte mic si foarte simplu in mai multe limbi. Sa zicem 3-5 pagini aproape statice, in vreo 2-3 sunt formuri cu cate ~ 10 campuri si un buton, cu etichete si cate un mic paragraf de text pe langa ele, in vreo 5-10 limbi.

Am cautat pe Internet, m-am documentat, sunt vreo 5 idei mari si late, nici una fantastica:
- client side 1: fiecare pagina are cate un ID la fiecare element cu text in el, incarca dintr-un JSON limba respectiva si o scrie in fiecare element; daca vrei sa schimbi limba vei avea alta pagina cu alt URL, ceea ce nu e o idee rea deloc, poate cineva vrea sa o puna in Bookmarks direct in limba pe care o vede pe ecran
- client side 2: acelasi lucru ca mai sus, dar se incarca dintr-un XML care contine doar limba dorita
- client side 3: la fel ca la 2, dar cu un XML care contine toate limbile. Mi se pare un pic ineficient.
- client side 4: varianta ciobaneasca, un include la un limba.js care initializeaza variabile cu textul care trebuie si il scrie in elementele care trebuie. E banal de implementat chiar si de indieni
- client side 5: se iau textele in limba dorita de la server prin AJAX. Interesant, dar de ce sa faci asa ceva?
- server side 1: un ceva gen PHP genereaza pagina direct in limba dorita, citind textele de undeva: JSON, XML, include ciobanesc cu variabile, dar sigur nu prin AJAX de la o alta componenta; aberatia are si ea niste limite.

Care ar fi cea mai buna varianta dintre cele de mai sus, eventual alta nepomenita in lista?

Intrebarea 2
Se da un server de web pe Internet, un form PUBLIC care face validari prin Ajax la un server aflat intr-un DMZ/Intranet/nu-pe-Internet si alte diverse servere in Intranet care se pot folosi. Se pot face urmatoarele arhitecturi:
- formul pe serverul extern, AJAX server-side in Intranet, acces public la acel script pentru ca un username si o parola client-side (utilizata de browser = accesibila oricui) e ca si cum nu ar fi
- totul pe Intranet, formul publicat printr-un reverse proxy/firewall rule

Pana la urma e vorba de ce se expune pe Internet, dar in ambele cazuri mi se pare ca expunerea e egala: atat formul cat si componenta server-side pentru AJAX sunt accesibile din Internet. Ca securitate e cam tot aia, ca sa te conectezi la un server (pentru AJAX) trebuie sa il vezi din browser, ca acolo se face conexiunea. Asa ca ma gandesc la varianta 3:
- form pe internet, se conecteaza la un server-side tot pe Internet care se conecteaza la alt server side in Intranet. Avantaje: conexiunea catre serverul din Intranet exista, dar nu stie nimeni unde e, de asemenea se poate securiza cu ceva autentificare si HTTPS.

Intrebarile:
- dezavantaje pentru varianta asta cu un soi de AJAX-proxy?
- cum se pot implementa credentials pentru apelurile AJAX - merge ceva gen http(s)://username:tongue:assword@server?
 
Întrebarea 1:
Aici eficiența se traduce în:
- ce e mai simplu pentru programator
- timp de încărcare
- dimensiune pagină (dacă nu hostezi singur și plătești bandwidth)

Ideea e ca dacă folosești fișiere de resurse (traducere), să fie statice, astfel încât să poată fi cached de server. Că-s JS, JSON, XML sau altceva nu e foarte grav.

În momentul ăsta aș folosi o bibliotecă de jQuery, gen https://github.com/wikimedia/jquery.i18n (definești un dicționar JSON, iar în tag-urile html scrii cheia din dicționar, știe și parametrizare, plurale, etc), cu locale-ul luat din parametrii paginii (ex: form1.html?locale=en), astfel încât poate fi și pus la bookmarks într-o anumită limbă. E plăcut să ai fiecare limbă în fișierul ei, compari mai ușor diferite versiuni, modifici mai ușor și nici nu încarci la fel de mult.


Întrebarea 2:

De lăsat oricum n-ar trebui să te lase nimeni să expui direct ceva din Intranet către exterior. În mod normal ai un server în DMZ, către care se duc toate cererile, și ăla face dispatch către backend-urile din Intranet. Serverul poate fi foarte simplu (câteva linii într-o configurare apache/nginx pentru reverse proxy), poate face load balancing sau routare L7 (haproxy, nginx etc) sau poate fi full-fledged (application server cu logică avansată în interior). În Intranet ai ce rămâne (application servers, baze de date etc). Între DMZ și Intranet ai de obicei un firewall care îți permite accesul doar de la serverul DMZ și doar pe porturile specificate, și poate încă un nivel de proxy/LB ca să nu expui prea multe mașini din Intranet către serverul din DMZ (1 server DMZ se conectează la 1 server din Intranet pe porturile X, Y, Z, iar serverul din Intranet se conectează la alte servere).

Apelurile AJAX se autentifică cu session ID în cookies (varianta de bază pentru apeluri stateful pe HTTP-ul stateless) sau ca parametru în fiecare call (de obicei fallback dacă nu acceptă utilizatorul cookies, sau dacă folosești un framework care implementează asta by default). Session ID-ul e primit atunci când accesezi pagina, după care e updatat când te loghezi (dacă există login). Pe server session ID-ul e asociat cu un obiect Session, care conține state-ul server-side. Când ai un apel AJAX, se identifică obiectul sesiune pe baza session ID și se updatează cu noile date.

Dacă întrebai cum se autentifică serverele între ele (cel din DMZ cu cel din Intranet), asta depinde de servere. O discuție interesantă e și unde termini sesiunea HTTPS atunci când ai o arhitectură cu proxy-uri. E mai simplu să o termini pe proxy, dar îl faci mai complex în cazul ăsta (și posibil mai vulnerabil, că-s cheile tale pe el).
 
Tocmai pentru ca e academica, discutia continua :smile:

1. Nu as folosi o biblioteca pentru traduceri, se poate schimba usor sensul din text din cauza unei traduceri subtirele. Libraria aia zice ca stie genuri si singular/plural, prefer traduceri statice verificate de oameni care vorbesc nativ limbile respective, mai ales ca e vorba de 5-6 limbi si nu 100.
Intrebarea ramane: limba in pagina construita client-side sau server-side?

2. Corecta intrebarea cu HTTPS-ul; clientul foloseste HTTP in pagina, pagina face un alt apel HTTP la componenta server-side de pe Internet care foloseste HTTPS pana la componenta din Intranet. Asta ar avea vreo cateva avantaje:
- nimeni nu stie de existenta serverului din Intranet
- daca totusi il gaseste, nu poate comunica din lipsa de username/parola
- comunicatia catre acel server e HTTPS, deci nu poti sa tragi cu ochiul ca sa furi username/parola.
 
1. Nu e vorba de bibliotecă pentru traduceri, e vorba de o bibliotecă pentru injectat traducerile (făcute de cineva, nu automate) în HTML. Partea cu singular/plural înseamnă doar că are suport pentru a-i putea pune ușor versiuni. Ex: ai textul "Ana are 1 măr" / "Ana are 2 mere" - în json vei scrie 'Ana are $1 {{plural:$1|măr|mere}}' (adică nu trebuie să-ți pui tu cod custom care să verifice if(nr>1) scrii "mere", altfel scrii "măr").

Cât despre server-side vs client side, push-ul acum este spre client side, ca să nu folosești servere prea puternice (care costă). Browserele sunt foarte puternice acum, device-urile pe care rulează la fel, cât mai multă logică în browser = server încărcat mai puțin (mai mic/ieftin sau pur și simplu mai ieftin dacă ești în cloud și ți se contorizează toate). Asta înseamnă că trebuie skills de js (jQuery/Backbone/Angular...). Resursele sunt JSON (parsare simplă în browser, gzip dacă-s mari, cached în browser), servite static de undeva (serverul tău sau CDN).


2. De "găsit", în cazul ăsta (cu setup-ul de care ziceam în post-ul anterior) serverul din Intranet poate fi găsit doar de pe proxy-ul din DMZ, adică atacatorul trebuie să ajungă pe acel server ca să poată face ceva, pentru că serverul din Intranet poate să nu aibă legătură cu exteriorul (routarea e doar între intranet și DMZ, nu iese pe Internet). Între proxy și Intranet pui ce vrei, doar că e mai complexă configurarea pentru ce zici tu (HTTPS doar între proxy și backend), iar toate datele necesare conexiunii vor fi oricum pe server-ul din DMZ. Și dacă ăla e doar un proxy, tot cam aia e dacă atacatorul vede sau nu comunicația aia.

Regulile de protecție DMZ zic că atunci când ai un sistem intern care trebuie expus către DMZ, conexiunea ar trebui făcută de la sistemul intern către DMZ (de la mai sigur la mai puțin sigur), dar în cazul ăsta e complicat.
 
Întrebarea 1, 2 variante:
1) server-side: scriptul face parsing la headerul HTTP pentru a afla Accept-Language cu lista completă de limbi (și ordinea lor) pe care userul le-a setat în browser, după care livrează conținutul în limba respectivă sau face fallback la un default; desigur, ai putea folosi această variantă ca secundară, presupunând că userii nu prea își schimbă de capul lor asemenea setări, și atunci mai bine faci întâi o verificare pe bază de IP (GeoIP) ca să identifici țara vizitatorului și să presupui limba corectă; într-un mediu corporate ai putea folosi vreun câmp din AD pentru userul autentificat pentru a-i determina țara/biroul/organization unit etc. și din care să derivi un default language;
2) client-side: documentul tău (X)HTML include întreg conținutul dorit, în DIV-uri separate identificate cu o limbă sau alta în interiorul body-ului, și browserul afișează doar varianta cu prima limbă selectată drept prioritară. E mai târșă actualizarea fișierelor, da' nu te complici cu server-side la nimic.

Parcă pe apache mai ai o posibilitate server-side să definești pagini gen index_en, index_fr, index_ro și să se prindă singur care din ele trebuie livrat în funcție de limba aleasă în browser, dar asta înseamnă mentenanță manuală la mai multe fișiere.

Best practices:
- definirea unei limbi pentru XHTML (una singură):
HTML:
<html lang="en" xml:lang="en" xmlns= "http://www.w3.org/1999/xhtml">
- definirea unei liste de limbi pentru care conținutul fișierului este relevant:
HTML:
<meta http-equiv="Content-Language" content="de, fr, it"/>
 
miahi, am inteles ce face libraria aia, dar daca eu am un form cu texte predefinite atunci 1 mar, 2 mere e un caz care nu exista niciodata si atunci nu stiu daca e nevoie de librarie pentru a folosi doar o mica parte din ce stie.
Partea cu client-side versus server side e corecta, doar ca eu ma astept la o incarcare atat de mica incat nu conteaza, gen 5000 de afisari lunar.

Pentru clarificare, in acest moment am 2 servere: unul in Internet, unul in Intranet. Formul va fi pe cel de Internet, comunica cu un PHP local (de care lumea poate sa afle usor), care comunica prin HTTPS cu cel din Intranet printr-un port din firewall. Sunt doar 3 componente atunci: pagina HTML din browser, PHP-ul cu care discuta pagina si un alt PHP de care nu se stie.

puterfixer, nu ma uit la limba setata in browser, pur si simplu pun 6 steaguri in header cu 6 URL-uri catre aceeasi pagina, dar cu limbi diferite. Utilizatorii sunt in mare parte afoni in computere, nici 1% nu ma astept sa stie cum sa isi seteze limba preferata si asta nici macar nu inseamna ca in aia vor sa vada pagina.

Formul e public pe Internet, nu exista AD si nici nu ma intereseaza geolocation in epoca proxy-urilor. Chiar si eu ma trezesc ca sunt pe Internet cu adresa de Singapore, nu dau 2 bani pe geolocation dupa IP.

Din pacate ideea de a avea cate un DIV, input, button etc. pentru fiecare limba nu ma atrage deloc; formul are o structura dinamica, in functie de alegerile la un pas merge pe diverse cai; e deja complicat, o gramada de JavaScript pentru asta, daca inmultesc totul cu 5-6 ca sa fie cate un set din fiecare limba imi examinez picioarele pentru locuri bune de impuscat; calibrul .22 ca sa o pot face de mai multe ori inainte de a ramane fara. O sa fie cate un singur element la care la incarcarea paginii se va incarca si limba, ceea ce nu imi e foarte clar e daca exista diferente notabile de simplitate in cod pentru a face asta in variantele JSON-variabile JS-XML. Am un proof of concept complet functional cu variabile JS si o singura limba, engleza, vreau sa ma lamuresc care varianta e mai buna inainte de a continua.
 
Pentru 5000 de afișări ai pierdut deja prea mult timp gândindu-te la soluții :smile:. Dacă ai deja POC-ul cu limba engleză în variabile JS, continuă la fel (cel mai simplu: câte un js pentru fiecare limbă, iar în funcție de limba aleasă încarci js-ul potrivit). Să testezi bine ce se întâmplă dacă cineva schimbă limba după ce a început completarea form-ului, să nu se piardă date (asta e altă chestie care-i faină la bibliotecile js, nu trebuie să te mai duci pe server/reload la toate schimbările de UI).

Pentru PHP server-side merge gettext - cu avantajul că ID-ul mesajului e chiar cheia, adică ai un call de tipul
Code:
$name = "Vic"; printf(_("Hello, %s, it is nice to see you today.\n"), $name);
care ajută la vizualizarea mai ușoară a codului (știi exact ce se va afișa) și a traducerii (în fișierul de traduceri ai ambele variante, și în limba de bază și tradus).
 
Cum fac urmatoarea chestie: un link intr-o pagina sa descarce un fisier .CSV care e generat pe loc ca rezultat al unui query? Stiu sa fac acel query si sa generez un .CSV, dar nu sa si returnez acel .CSV ca rezultat al linkului. Preferabil in PHP, daca tot nu stiu PHP :smile:

O idee aparent cretina e sa pun link catre "http://server/fisier.csv" si sa interceptez apelul printr-un PHP (module mapping --> *.csv catre php.cgi.exe), iar PHP-ul sa returneze continutul care ar fi in .CSV, dar are si asta vreo 2 probleme: ar face asta pentru orice CSV - nu e o problema, sa zicem - si nu stiu cum ar reactiona browserul la asa ceva, eu vreau ca rezultat ca acel .CSV sa fie salvat local, nu deschis in browser pentru ca nu ai ce face cu un fisier cu 30.000 de linii in browser, ci doar sa il descarci si sa il deschizi in Excel.
 
Setezi headerele din PHP ca browser-ul să vadă că e CSV și nu HTML. Nu contează extensia link-ului de pe server, poate fi http://server/blabla.php și tot îți servește csv
Code:
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=fisierulmeu.csv');
după care în continuare faci output (în PHP) ca și cum ar fi un csv (fputcsv + fopen("php://output") te ajută).

Vezi că headerele trebuie scrise chiar la începutul paginii (să nu mai ai nimic înainte de apelul header()).

Posibil să fie nevoie în content-type și de charset, dacă ai chestii speciale pe-acolo.
 
Last edited:
Partea cu output o stium nu e o problema, dar ca sa ma lamuresc complet, logica ar fi cam asa:
- eu pun un link http://server/ceva
- acel ceva e un PHP care incepe cu setarea headerelor, face query si arunca outputul catre browser - cand browserul primeste asa ceva crede ca e un fisier csv si foloseste meniul "dowload/save as/open"? Nu se asteapta, de pilda, ca in output sa fie si un end of file pe care eu nu cred ca il trimit?
 
Ce a zis miahi, dar iti trebuie <?php inainte de header().
apoi continui cu
echo("A1,A2,A3\r\nB1,B2,B3\r\n");
sau ce doresti sa contina fisierul.
Daca faci si operatii I/O sau cu baza de date, ai grija la posibilele erori afisate. Ele vor apare in fisierul downloadat, nu in browser. Practic, dupa acel header, tot ce produce PHP-ul va ajunge in fisier.

LE:
Eu n-as incepe cu setarea headerelor. Daca ai vreo eroare in program si ai trimis headerele, eroarea va ajunge in fisier, nu in pagina browserului.
Fa asa:
Proceseaza tot ce ai de procesat pana cand obtii continutul complet al CSV-ului, totul fara sa afisezi nimic. Daca intalnesti erori, afiseaza HTML cu errorile, inchide HTML si fa exit fara sa mai incerci sa trimiti headerele si CSV-ul. Sau poti trimite in continuare CSV-ul partial ca sa vezi mai usor unde s-a produs eroarea.
Daca nu ai erori (si nici n-ai afisat nimic pana aici), trimite headerele si apoi echo cu ce trebuie sa contina CSV-ul.

Da, browserul va crede ca este un CSV obisnuit. Header-ul cu content type ii spune asta. Al doilea header este acolo ca sa iti afiseze optiunea de download in loc sa iti prezinte continutul CSV intr-o pagina text. Il poti omite in timpul testelor ca sa iti fie mai usor.
Nu trebuie sa trimiti EOF. EOF apare automat cand se termina executia PHP-ului.
 
Last edited:
Cu setarea header-ului după: depinde cât de mare e fișierul, dacă îți convine să-l păstrezi pe tot în memorie sau nu.
 
Nu-i nevoie sa il pastrezi in memorie. Poti scrie pe disc in fisier temporar, apoi resetezi pointerul de la inceput si trimiti headerele fix inainte sa citesti din el.
Daca folosesti CSV-ul pentru procesari ulterioare automatizate, nu-ti doresti sa gasesti o eroare PHP in el.
Dar inteleg si varianta ta; daca faci un DB-dump si te uiti de fiecare data in acel CSV inainte sa faci orice altceva cu el, metoda directa e mai rapida.

PS: am uitat sa zic. CGI-urile au limita de timp la executie, indiferent daca fac output sau nu. Daca depasesti limita de timp, trebuie sa verifici in doua locuri: limita hard impusa de serverul web si limita soft din php.ini. E soft pentru ca o poti prelungi in timpul executiei cu set_time_limit().
 
Nu mai are treaba cu HTML-ul, dar ca sa nu mai deschid inca un topic doar pentru o intrebare:

Pe un server Windows pe care exista si PHP instalat e nevoie de un script care sa ruleze la 15 minute. Se poate face in n limbaje de programare sau scripting, compilate sau interpretate sau semi-compilo-interpretate (aka .NET), dar care e varianta recomandata intre PHP si C#? De ce le-am luat doar pe astea in calcul:
- ca sa nu va pierd timpul cu toate celelalte optiuni care pica din diverse motive
- scriptul se conecteaza la o baza de date, citeste niste chestii, apeleaza niste web services, timite cate un mail sau mai multe si eventual mai face un status update in baza cu ce a facut. Asta inseamna ca sunt de preferat limbaje mai strong-typed ca sa nu iasa incurcaturi jenante cu tratarea datei in functie de regional settings de pe server, cum am mai vazut. PHP are PDO, C# e strong-typed, ambele indeplinesc conditiile
- astea doua nu necesita nimic instalat sau configurat, ca sunt deja acolo
- amandoua pot rula prin Scheduled Tasks fara complicatii
- amandoua sunt vechi, cunoscute, destul de fiabile, se gasesc usor oameni care sa se uite in ele in viitor daca e nevoie de reparat ceva, schimbat cate ceva, adaugat modulul de facut clatite cu dulceata de zmeura
- amandoua au cat de cat un viitor, fata de limbajele minune care apar ca ciupercile si dispar cand se plictiseste prietena dezvoltatorului sa se uite singura la filme in timp ce el mai adauga un feature sau carpeste securitatea codului existent

In afara faptului ca C# are un suport mult mai bun pentru depanat erori (PHP poate manca ficatii lejer, gen cod care merge la un utilizator si nu merge la altul sau cod care dupa un copy/paste nu a mai mers, dar stearsa linia respectiva si scrisa din nou din tastatura merge), dar PHP are o functie foarte misto pe care nu am gasit-o in C#: strtr (e fenomenala daca vrei sa scrii un mail pe baza unui template), mai exista chestii pro sau contra semnificative?

PS. Versiuni: C# si .NET 4.5, PHP 5.6.* pentru ca PHP 7.* nu are inca driver pentru MS SQL, baiatul de la Microsoft care lucreaza la el zice ca mai dureaza 2-3 luni, probabil pentru ca va include si suport complet pentru SQL 2016.
 
N-am folosit C#, dar cu PHP fac chestii din astea in mod curent. Mail-uri nu am trimis cu PHP 5.x dar am folosit Fake Sendmail cu PHP 4.
In general merge fara probleme, dar cod care sa iti manace ficatii am intalnit si eu din cand in cand. PHP4 nu suporta HTTPS, PHP5 se crashuie la un PCRE fara nici o eroare... Apelez PHP4 din PHP5 si invers ca sa "trec" de diverse probleme.
 
Partea cu emailul in PHP 5 e simpla, am deja cod scris care functioneaza impecabil, nu am nici o frica. Asta, STRTR, CURL si faptul ca exista bucati de cod deja scrise in PHP gata de reutilizat sunt cam toate motivele pentru care am luat in calcul PHP-ul.
 
Nu cred că și-au pus mai mult de 3-4 oameni problema "pot face un scheduled task în Windows în PHP sau C#, ce aleg?", ca să existe cale bătută (recomandată) - aici alegerea e C# by default. Cred că-s foarte puțini și cei care ar porni un script PHP în command line în Windows. Dar asta nu înseamnă că C# e cea mai bună alegere pentru tine, dacă ai cerințe care sunt simplificate de PHP (inclusiv cod scris deja), go for it.

Problema în astfel de decizii e mai mult de mentenanță - cei care întrețin codul PHP și serverul vor trebui să știe că există și acel scheduled task, și ce folosește, ca să se poată face o analiză de impact în cazul modificării aplicației inițiale.
 
Păi nu prea văd ce ar fi, din câte înțeleg e un program relativ simplu, iar deciziile importante au fost deja luate (ex: faptul că va fi un eveniment scheduled și nu triggered de aplicație, faptul că se va folosi Scheduled Tasks și nu un scheduler specific aplicației). Problemele rămase sunt mai mult de orchestrare și nu strict tehnice (ex: ce se întâmplă dacă rularea depășește cele 15 minute alocate și se "prind din urmă" rulările) sau tehnice comune (ex: văzut dacă task-ul rulează perfect când nu există utilizatori logați în sistem, monitorizare că s-a executat task-ul corect).

Eu în afară de backup-uri scheduled nu prea am folosit Scheduled Tasks, prefer un scheduler în aplicație (uzual Quartz) pentru că poți să-l controlez mai ușor direct din aplicație (ex: poate la anumite acțiuni din aplicație trebuie să oprești executarea task-urilor, sau task-ul depinde strict de niște servicii ale aplicației și atunci n-are rost să ruleze când nu e aplicația pornită).
 
Back
Top