ugrás a tartalomhoz

Include és a változók

eddig bírtam szó nélkül · 2012. Jún. 18. (H), 07.28
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.

$x=1;
include "x.php"
...
és az x.php felhasználja, esetleg átírja a $x értékét.
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.
 
1

Ne használj globális

Hidvégi Gábor · 2012. Jún. 18. (H), 08.46
Ne használj globális változókat, és akkor nem lesz ilyen gondod.
2

Akkor pontosítsunk: én azt

eddig bírtam szó nélkül · 2012. Jún. 18. (H), 08.54
Akkor pontosítsunk: én azt írtam, egy általam szakembernek tartott tagnak, hogy "letörném a kezét annak, aki ilyet elkövet". Erre kaptam egy másfél oldalas magyarázatot, ami szerinte indokolja az ilyesmit, utalva pl. a session management működésére.
Én itt feladtam a dolgot, de mint mindig, most is megvan bennem a kétség, hogy esetleg valamit én tudok rosszul.
5

Session

janoszen · 2012. Jún. 18. (H), 09.28
Erre azert kivancsi lennek. Aki a session managementet OOP kornyezetben $_SESSION-bol oldja meg, az nem ertette meg az OOP lenyeget.
6

Bár ez független az eredeti

eddig bírtam szó nélkül · 2012. Jún. 18. (H), 09.35
Bár ez független az eredeti témától, de én biztosan nem kezdenék új session manager környezetet írni, így viszont keretrendszerek ismerete hiányában egy bizonyos pontig kénytelen vagyok a $_SESSION-re hagyatkozni. (és akkor még ott vannak a $_GET, $_POST és hasonlók, amiket végképp macerás megkerülni)
8

Mindenkeppen

janoszen · 2012. Jún. 18. (H), 12.48
Ha OOP kodot irsz, mindenkeppen kell elfedo osztaly a szuperglobalisokra, tobb okbol is:

  • A PHP sajat session kezeloje nagyon nehezen debuggolhato, ha baj van vele. Ha le akarod cserelni egy sajat implementaciora, szinten csak hackelessel valosithato meg.
  • Ha szuperglobalist hasznalsz, eselytelen vagy barmifele modositast vagy access controlt vegezni az adaton, ha ugy szeretnel kesobb tenni.
  • A kododat nehez lesz tesztelni, ha mindenki kozvetlenul tur a sessionben.
  • A szuperglobalisok megvalositjak a god object (ez esetben array) patternt.


Ha meg 5 percig gondolkoznek, biztos egy rakas dolog eszembe jutna.
9

szuperglobálisok

eddig bírtam szó nélkül · 2012. Jún. 18. (H), 14.10
No várj! Én csak azt mondtam, hogy ezeket megkerülni/kihagyni a játékból... hát legalábbis problematikus.
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?
21

Kis megjegyzés

Pepita · 2012. Jún. 19. (K), 23.32
Szép hosszú - és jó - téma, csak egy pici javaslat:
...keretrendszerek ismerete hiányában...

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

include

Poetro · 2012. Jún. 18. (H), 09.01
Az include lényege, hogy a kódod úgy működik, mintha az include-olt kód oda lenne "bemásolva", ahol az include 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.
4

Félreértettél te is...

eddig bírtam szó nélkül · 2012. Jún. 18. (H), 09.08
Elvi problémám van a dologgal: értem én, hogy mit művel az include és hogy ez működhet.
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.
7

Kerülendő

Hidvégi Gábor · 2012. Jún. 18. (H), 09.56
Tökéletes megoldás nincs, amíg a forráskódhoz mindenkinek van hozzáférése; például zéró energiabefektetésbe kerül egy private-et átírni public-ra stb.
10

nem ez a gond.

pp · 2012. Jún. 19. (K), 07.53
A kódból nem derül ki, hogy
  • nem lehet átírni,
  • át lehet írni,
  • át kell írni

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
12

Én is erről beszélek

Hidvégi Gábor · 2012. Jún. 19. (K), 08.40
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.
Pontosan ezt gondolom én is; a private-public példát arra írtam, hogy mennyire könnyű a kód megértése nélkül hibát okozni, és az ilyeneket nem nagyon lehet kivédeni.

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

Nem csak a globális változókat éri el

pp · 2012. Jún. 19. (K), 08.00
hozzáfér az összes globális változóhoz

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
13

És akkor jöjjön egy nagyszerű

nova76 · 2012. Jún. 19. (K), 08.42
És akkor jöjjön egy nagyszerű példa arra, hogy hogyan kellene ezt szépen megvalósítani. Nyilván nem az a megoldás hogy nincs include, mert a spagettti kód sem szép.
14

Ha az include a "spagettit"

eddig bírtam szó nélkül · 2012. Jún. 19. (K), 08.51
Ha az include a "spagettit" hivatott eltüntetni, akkor rég rossz, szerintem.
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 :-)
15

Valóban arra való. :-)

nova76 · 2012. Jún. 19. (K), 09.31
Valóban arra való. :-) De!
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.
28

Több echo?! Csak én gondolom

deejayy · 2012. Jún. 20. (Sze), 18.44
Több echo?!

Csak én gondolom úgy, hogy egy darab szövegkiírási műveletnek lenne szabad helyet foglalnia a index.php utolsó sorában?
16

valami.inc <?php function

pp · 2012. Jún. 19. (K), 17.13
valami.inc

<?php 
function nem_tudjuk_mit_csinal(&$x) {
  ...
}
?>
Ahol include-olunk.php
<?php
include('valami.inc'); // inkább include_once, vagy méginkább require_once
$x = 1;
nem_tudjuk_mit_csinal($x);
?>
17

Akkor próbáljuk meg mondjuk

nova76 · 2012. Jún. 19. (K), 17.38
Akkor próbáljuk meg mondjuk megvalósítani egy user formot és egy bemutatkozó oldalt.
Az $x lenne a te példádnál maradva user

show.inc

<?php   
function show($x) {  
  ?>
     <div><strong>Név:</strong><?php echo $x->name ?></div>
  <?php
}  
?>  
edit.inc

<?php   
function edit($x) {  
  ?>
     <form>
       <div><label for="name">Név:</label><input type="text" value="<?php echo $x->name ?>" /></div>
     </form>
  <?php
}  
?>  
index.php

<?php 
$x = db::findUser($_POST['id']);  
$feladat = $_POST['feladat'];
include($feladat.'.inc');
call_user_func($feladat, array($x));
?>   
Így gondoltad?
19

így biztos nem gondoltam...

pp · 2012. Jún. 19. (K), 22.34
í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
22

Nem egészen

eddig bírtam szó nélkül · 2012. Jún. 20. (Sze), 06.07
Az eredeti felvetésben (már ha az enyémet tekintjük eredetinek) épp az volt, hogy szabad-e olyan kódot írni, amely belepiszkál ama bizonyos $x-be?
24

Akkor félreértettelek.

pp · 2012. Jún. 20. (Sze), 06.50
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)
25

Végeredményben erről beszélek

eddig bírtam szó nélkül · 2012. Jún. 20. (Sze), 07.11
Végeredményben erről beszélek én is, csak nem gondoltam végig a lehetséges problémákat.
23

Először is nem volt feltétel,

nova76 · 2012. Jún. 20. (Sze), 06.30
Először is nem volt feltétel, csak lehetőség. De pont azt akartuk elkerülni hogy lehessen. Ezért én a referencia jelet dobtam is a kódból.
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?
26

Ez így hosszú lesz. :)

pp · 2012. Jún. 20. (Sze), 07.24
Először is nem volt feltétel, csak lehetőség. De pont azt akartuk elkerülni hogy lehessen. Ezért én a referencia jelet dobtam is a kódból.

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

Harmadszor pedig hogyan függne már össze? Annyiban függ össze, mint amennyiben most, ugyanazzal az objektummal szeretnék dolgozni.


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.

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


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.)
27

1, a topik bevezetőben épp

nova76 · 2012. Jún. 20. (Sze), 10.42
1, a topik bevezetőben épp azt ecsetelte a topik nyitó, hogy mennyire rossz hogy belenyúl a változóba. Mert akkor nehézkessé válik a debug. Ez pedig akkor azt jelentheti nála, hogy Ő kizárólag osztályokat, függvényeket includeol. De ügye attól még meg kell oldani azt is hogy egy webes alkalmazás/ vagy bármi nem egyetlen feladatot lát el. Valahol be kell hoznom a templatet is, amiből lehet akár több 100 is.

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

nem véletlen, hogy az

tgr · 2012. Jún. 20. (Sze), 21.11
nem véletlen, hogy az allow_url_open php paraméter ki van kapcsolva


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

Hivatkozásként átadni a

eddig bírtam szó nélkül · 2012. Jún. 19. (K), 18.01
Hivatkozásként átadni a paramétert? Ilyet én csak végszükség esetén követnék el. Ez hiba?
Szerintem inkább átadom a paramétert és a függvény visszatérési értékével dolgozom tovább.
20

nem, semmi esetre se.

pp · 2012. Jún. 19. (K), 22.40
A kóddal csak azt próbáltam szemléltetni, hogy így lehet jelezni, hogy módosíthatja a fv a változót. (egyértelműen egy class publikus változója, vagy egy setter függvény szebb megoldás lenne, de itt a semminél több volt a cél)

pp
29

Template vagy egyszerű konfig

tgr · 2012. Jún. 20. (Sze), 21.02
Template vagy egyszerű konfig fájl (php tömb) esetén tudnám elfogadni, de akkor se módosíthasson (az include hívás után az adott függvény végéig már ne használjon változókat). Sima PHP template-eknél viszonylag bevett megoldás (pl. a Drupal így csinálja).