Include és a változók
Másik fórumon került szóba, de... Na mindegy, szóval kíváncsi lennék a ti véleményetekre.
Adott egy PHP program, ami itt-ott include-dal betölt egy kódrészletet és az így betöltött részben az include-ot kiadó környezet változóit használja.Nekem szokás szerint, eléggé... khm... "sarkos" véleményem van a dologról. :-)
Szerintetek ez mennyire kulturált megoldás?
Én egyetlen esetet tudok elképzelni, amikor elfogadhatónak tartom: ha template-ként PHP-t használok. Bár ott is vannak kétségeim.
■ Adott egy PHP program, ami itt-ott include-dal betölt egy kódrészletet és az így betöltött részben az include-ot kiadó környezet változóit használja.
$x=1;
include "x.php"
...
és az x.php felhasználja, esetleg átírja a $x értékét.
Szerintetek ez mennyire kulturált megoldás?
Én egyetlen esetet tudok elképzelni, amikor elfogadhatónak tartom: ha template-ként PHP-t használok. Bár ott is vannak kétségeim.
Ne használj globális
Akkor pontosítsunk: én azt
Én itt feladtam a dolgot, de mint mindig, most is megvan bennem a kétség, hogy esetleg valamit én tudok rosszul.
Session
Bár ez független az eredeti
Mindenkeppen
Ha meg 5 percig gondolkoznek, biztos egy rakas dolog eszembe jutna.
szuperglobálisok
Hogy kell egy osztály/objektum, ami ezt eltakarja az alkalmazás elől, az egy más téma.
A $_SESSION-t még ki is lehetne hagyni, csak nehézkes és sok hibalehetőséget rejt, amennyire anno utánanéztem.
De a többiek? Legalább egy helyen, egy osztályban kénytelen vagy használni őket, nem?
Kis megjegyzés
Vannak nagyon egyszerű, könnyen megtanulható, jól fejleszthető keretrendszerek is, érdemes valamit használni. Én a CodeIgniter-t részesítem előnyben, mert kicsi, egyszerű, stb. Persze egy ilyen egyszerűbb fw. alatt többet kell programozni (mint pl. Zend), de még mindig jóval kevesebbet, mint nulláról. És amit egyszer jól megírtál (osztályt, helpert, stb), azt később is újrahasznosíthatod.
Szerk.: Ja, és a betöltéseket ("include") többnyire jól és biztonságosan megoldják helyetted.
include
include
lényege, hogy a kódod úgy működik, mintha azinclude
-olt kód oda lenne "bemásolva", ahol azinclude
van (kicsit ennél bonyolultabb, de elég jól közelít a valósághoz). Azaz, ha include-olsz, akkor az include-olt kód lefut, miközben hozzáfér az összes globális változóhoz. Ezért, ha nem szeretnéd, hogy véletlenül egy kód felülírjon egy globális változót, akkor ne tedd a változót globálissá. Van rengeteg egyéb eszköz adatok tárolására, amik lehetővé teszik a hozzáférést, de véletlenül nem fogod azokat felüldefiniálni.Lehet például
static
változókat és objektumokat használni a szükséges adatok tárolására és visszaadására.Félreértettél te is...
Nekem azzal van gondom, hogy valaki egy include-olt egységből piszkálja az őt behívó környezet változóit. Megteheti, de én úgy gondolom, ettől kuszává, nehezen értelmezhetővé válik a kód, ergo kerülendő ez az út.
Kerülendő
nem ez a gond.
az x változó értékét, nem beszélve a többi változóról.
Persze lehet megjegyzést is írni, mindkét helyre, de lehet olyan nyelvi megoldásokat használni amik dokumentálják ezt a dolgot. Pl. az include-ban csak egy függvény definíció van amit meghív emberünk átadva neki az x változót. Így aki az include-oló kódban turkál tudja, hogy mi volt a cél, míg az include-olt kódban turkáló szintén tisztába lesz az x változó ilyen irányú hovatartozásával.
Arról most ne beszéljünk, hogy ha ezt a valamit esetleg egy ciklusba akarja berakni valaki ahol előszeretettel használja az $i változót, és az include-olt kódban is van egy ciklus ahol szintén pont az $i változót használják.
Szóval itt nem arról van szó, hogy ha valaki hibát akar okozni az tud, vagy nem tud hibát okozni, hanem arról, hogy ha valaki el akarja kerülni a hibát, igencsak nehéz dolga lesz.
Én kíváncsi vagyok, milyen érvek szólnak egy ilyen kód mellett.
pp
Én is erről beszélek
Szerintem érdemes egy programozási útmutatót írni, és az új kollegáknak betanítani, valamint a munka különböző fázisaiban egy felelős programozónak átnézni az általuk írt kódot, hogy megfelel-e a listának, amíg erre szükség van.
Nem csak a globális változókat éri el
Nem csak a globális változókhoz fér hozzá, hanem az adott scope-on belüli összes változóhoz. Tehát hiába nem teszi a változót globálissá, azt az include-olt kód simán felül tudja vágni. (arra koncentráljunk ami a példában szerepel)
pp
És akkor jöjjön egy nagyszerű
Ha az include a "spagettit"
include/require SZVSZ olyan célokra alkalmazható, mint pl. különböző eljárásgyűjtemények betöltése.
Hm?
Persze az is igaz, hogy sokak szerint emberiség elleni bűntett az is, hogy echo-val írom a megjelenítendő HTML-t :-)
Valóban arra való. :-)
Valahogy az adatokat csak meg kell jelenítened. És általában indulsz egy index.php-ból. Tehát hogy jutunk el oda, hogy megjelenítjük a user adatait, vagy épp egy cikk tartalmát?
"Persze az is igaz, hogy sokak szerint emberiség elleni bűntett az is, hogy echo-val írom a megjelenítendő HTML-t :-)" az emberiség elleninek nem nevezném, inkább csak a kollégák elleni. Én különösen akkor szoktam elveszni, amikor a nyitó tagot valami függvény írja ki, a záró tagot meg csak úgy html-ként, aztán párosíts, ha valami gond van. Az include itt is bejátszik (lehet include_partial is, mint mondjuk symfonyban), láttam már olyat hogy az egyik template fájlban megkezdték a html elemet, és a másikban lezárták. Ezt kicsit megcsavarod 4-10 fájllal, meg echokkal és elrejtesz benne egy aprócska hibát (persze nem szándékosan csak véletlenül, hiszen talán Te is hibázhatsz) és lehet bogozni egy napon át. Főleg az a nagyon jó, amikor hetekkel hónapokkal később derül ki, mikor valaki megnézi IE alatt is, és hiányzik mondjuk az oldal alja.
Több echo?! Csak én gondolom
Csak én gondolom úgy, hogy egy darab szövegkiírási műveletnek lenne szabad helyet foglalnia a index.php utolsó sorában?
valami.inc <?php function
Akkor próbáljuk meg mondjuk
Az $x lenne a te példádnál maradva user
show.inc
így biztos nem gondoltam...
Először is a call_user_func szerintem a referenciát nem szereti, tehát belepiszkálni a változóba nem lehet, pedig ez egy kérés volt az eredeti feltevésben.
Másodszor, szó sem volt dinamikus include-ról.
Harmadszor, biztos, hogy űrlap kezelést így nem csinálnék, mert a megjelenített űrlap elemek és azok feldolgozása elég szorosan összefügg.
Negyedszer, biztos, hogy nem tárolnék adatbázisba olyan formátumba ahogy azt megjelenítem, vagy az űrlap elemhez beteszem.
Ötödször, felhasználótól jövő adatot így még mintakódba se dolgoznék fel.
Az általam vázolt kód (amit nem használnék), pusztán azt a problémát kezeli, hogy egy teljességgel hasznavehetetlen, debugolhatatlan kódom van.
pp
Nem egészen
Akkor félreértettelek.
Azzal a kóddal nem az a baj, hogy az $x-be bele tud nyúlni, ha akar, hanem az, hogy bármilyen, a scope-ban elérhető változóba bele tud nyúlni, ha akar, ha nem.
Tehát az eredeti kóddal az a bajom nekem személy szerint, hogy úgy is tudsz hibát okozni, hogy nem akarsz, amit csak úgy tudsz elkerülni, ha az egész kódot ismered és a fejedben tartod.
Márpedig az egész kódot ismerni és fejben tartani nagy projekt, vagy sok kisebb projekt esetén lehetetlen(vagy, ha nem is lehetetlen - Rain Man ugye -, de biztosan felesleges :)). Mert ugye minek is toltuk külön fájlba a kódot ugye...
Egy ilyen kódot folyamatosan supportálni, fél év múlva módosítani biztosan hajtépés és akkor még csak egyedül dolgoztál és nem csapatban, mert akkor már az elkészítésnél is gondok lesznek.
Az, hogy egy változót lehet-e módosítani az már egy huszadrangú kérdés, pláne PHP-ban, hisz objektumot mindig referenciaként adja át, a tömböknél meg halál viccesen működik (ember legyen a talpán aki megmondja, hogy értékként, vagy referenciaként kerül átadásra)
Végeredményben erről beszélek
Először is nem volt feltétel,
Másodszor dinamikus includról valóban nem volt szó, de egyértelműen kell. Az semmiképp sem megfelelő ha az index.php-ba minden egyes új funkciónál beleteszel egy újabb elágazást.
Harmadszor pedig hogyan függne már össze? Annyiban függ össze, mint amennyiben most, ugyanazzal az objektummal szeretnék dolgozni.
Negyedszer, és miért nem? És hogyan tárolnád akkor? Most ügye egy név tulajdonságról van szó, mert egyelőre ennyit írtam le. Ezt el se tudom képzelni hogy hogyan lehetne más formátumba. Vagy nem értem amit írsz.
Ötödször, miért is nem? A db osztály levédi az sql injectiont. Esetleg a function paraméterbe lehet belekötni, hogy nem lehet levédeni a hibát, vagy valami php függvényt ír a helyére valamelyik hacker palánta.
Én simán kihagynám a függvényt és függvényhívást is a kódból, de akkor az eredeti probléma jönne szembe. Ezért kérdeztem hogy akkor hogy. :-) Ugyanis lényegtelen hogy az $x vagy a user objektum adatai változnak-e, az include után már nem csinálok semmit vele. Ez az eredeti terv mindvégig, akkor miért is kellene vigyáznom rá, hogy ne változzon?
Ez így hosszú lesz. :)
Van amikor jól jön, van amikor nem, hogy bele lehet nyúlni egy változóba. (pl. az array_shift() vagy array_pop() függvény miért is ne lenne jó)
Nem egészen, mert a html-ben használt name paraméter alapján fogod keresni a POST/GET tömbben az értéket. Tehát ha valaki eltossza a html-edet akkor nem fog működni a kódod.
Első körben ezzel az a baj, hogy végig kell gondolnod, hogy milyen hiba is lehet ebből. Ez egyrészt idő, másrészt csak az általad eddig ismert támadási módok ellen véd, ami gyakran kevés, mint alant láthatjuk. :)
Második körben pedig olvasd el a példa alatt található figyelmeztetést.
Röviden beposztolok neked egy olyan $feladat-ot, hogy http://palocz.hu/tokmindegy és a http://palocz.hu/tokmindegy.inc fájlba pedig beteszek egy tetszőleges PHP kódot ami már a Te szervereden fog futni, lévén az enyém nem értelmezi a .inc kiterjesztésű fájlokat. Tehát tetszőleges kódot tudok futtatni a szervereden.
Hogy ez mennyire gáz az mutatja az, hogy amikor egy kedves ismerősömnél rákérdeztem, hogy na akkor megkapta-e az ímélt amit az ő szerverén át küldtem, hisz beszéltük, hogy megmutatom, milyen egyszerűen hekkelhető az oldala, akkor egy döbbent csend után a "Te voltál?" kérdés hangzott el és egy történet, hogy egy hete milyen idegfrászban van a rendszergazda, mert nem tud rájönni, honnan jött a levél.
Lényeg, hogy a felhasználói inputot mindig ellenőrizzük, és csak olyat engedünk amit várhatunk, hogy a váratlan helyzeteket ne lehessen kihasználni. (pl. belerakod egy tömbbe a lehetőségeket, akár kézzel akár automatikusan felolvasva az adott könyvtárat ahonnan include-olni fogsz.)
1, a topik bevezetőben épp
2., "Nem egészen, mert a html-ben használt name paraméter alapján fogod keresni a POST/GET tömbben az értéket. Tehát ha valaki eltossza a html-edet akkor nem fog működni a kódod." Most nem értem, mit akarsz ezzel. Mert Te nem írtad meg hogy Te hogy csinálnád. Nem olyan hosszú az a kód, amit leírtam hogy ne tudnál belejavítani. :-)
De ha jól értelmeztem, akkor az a baj, hogy a kapott POST/GET tömbben a "name" lesz a kulcs. És ha valaki mondjuk azt írja hogy "nane", akkor én hiába várom. Ebben teljes mértékig igazad van. Csak a kérdés az, hogy hogyan tudnám ebben megakadályozni. Lévén hogy az a valaki készíti a form html részét, aligha tudok bármit tenni. Az is lehet hogy nem készíti el és én egy üres fájlt fogok kiíratni az includedal. :-) A kód attól még működni fog, mert a validálás után visszadobom hogy nincs a name mező kitöltve. Már feltéve hogy legalább a form megvan, hogy postoljon :-)
3., teljes mértékig igazad van ezzel az includos dologgal is, de azért tegyük hozzá hogy nem véletlen, hogy az allow_url_open php paraméter ki van kapcsolva. Ennek ellenére mégsem hiszem hogy ezt a problémát még ennek a paraméternek a bekapcsolása esetén is nem lehetne globálisan kezelni. Például úgy hogy elé teszed az include könyvtár útvonalát és megnézed hogy nincs a nevében más csak /*[a-z]*/. Máris nincs szükség rá, hogy állandóan szerkeszd ezt a fájlt, és mégis biztos hogy csak a helyi fájlok(azok is egy bizonyos könyvtár alatt lehetnek) közül választhatsz.
nem véletlen, hogy az
Egyrészt az esetek 99%-ában nincs, másrészt az se nyújt sok védelmet, ha bármilyen fájlfeltöltésnél (pl. kép) ki tudja találni a user a feltöltött fájl nevét, abba már teheti a PHP kódot. Vagy beincludeolja az apache hibalogot, és egy nemlétező URL-be ír PHP-t. Vagy beinklúdolja a password fájlt, kihasználva a PHP csodás "mindent kiechózunk, amíg nyitótaghoz nem érünk" feature-jét. Stb.
Hivatkozásként átadni a
Szerintem inkább átadom a paramétert és a függvény visszatérési értékével dolgozom tovább.
nem, semmi esetre se.
pp
Template vagy egyszerű konfig