9.10. Változók átadása oldalak között

Default book

Hogyan lehet értékeket átadni a PHP oldalak között, hiszen ha egy lap lefut, akkor a lapon keletkezet változók megszűnnek. Amikor először szembekerültem a problémával, akkor azt hittem, hogy a globális változók oldják meg a problémát. Sajnos a dolog nem ennyire egyszerű, de nem is túlságosan bonyolult. Átadhatunk egyedi változókat és egy dimenziós tömböket is. Négy lehetőségünk van erre.

Header utasítás

A Header utasítást csak akkor használhatjuk, ha az adott oldalon még semmiféle képernyőre írás nem volt, azaz a keletkező HTML oldal tartalmi részét még nem kezdtük írni. A header segítségével bármilyen header-t elküldhetünk. Az alábbi példában egy teljes header sorozatot írunk ki a HTML oldalra

header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");    // Date in the past
header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");    // always modified
header ("Cache-Control: no-cache, must-revalidate");  // HTTP/1.1
header ("Pragma: no-cache");                          // HTTP/1.0
header ("HTTP/1.0 404 Not Found");      

Itt egy hibakezelést írunk ki, az URL nem található. Akkor lehet ilyet tenni, ha például az Apache szerverünk hibaüzeneteit átirányítjuk a saját oldalainkra.

header ("HTTP/1.0 404 Not Found");

Böngésző átirányítása. Itt adhatjuk meg az új oldalt. Ez a parancs nem csak a böngészőt vágja át az új oldalra, hanem a szervernek is visszaküld egy átirányítás státusz üzenetet is. Sajnos ez nem igazán az, amire egy programozónak szükséges van!

<?php
  header ("Location: http://www.php.net"); /* Átirányítja a böngészőt a PHP web oldalra */
  exit;                 /* Ha nem megy az átirányítás, akkor az exit parancs biztosan kilép */
?>

A HTML szabványban azonban kitalálták az oldalak hívásainak módszereit (metódus) és ebből rögtön három is született, amiből kettőnek van szerepe.

GET metódus

A GET metódust úgy használhatjuk, hogy meghívunk egy lapot az oldalunkról egy másik lapot és az URL végére paraméterként átadjuk a változókat, valahogy így, ahogy a következő példákban látjuk:

Az első példában igazából nem is PHP a megoldás, egyszerűen a <BODY> TAG-ben megadjuk, hogy melyik oldalt és menyi idő múlva hívja meg az oldal. Ennek a megoldásnak hibája, hogy tulajdonképpen itt egy Javascriptet használunk. A példában 3 másodpercig vár a betöltődés után a böngésző, majd a szerver átdobja az új oldallal és meghívja a lapot a user, pwd és a level változókkal.

<BODY OnLoad=timerID=setTimeout('location="index.php?user=anonym&pwd=anonymous&level=1"',30000)>

A következő példában hasonlót teszünk, de itt a HTML oldal fejlécében dolgozunk. Felhasználjuk a HTML meta tag-ját. Itt is 3 másodperc múlve hívja be a következő oldalt és az előző oldalról átadjuk az előző példában látott 3 változó pillanatnyi értékét.

<meta http-equiv="refresh" content="3; URL=<index.php?<?php echo ’user=$user&pwd=$pwd&level=$level’ ?>">

A harmadik példában a PHP header utasítását használjuk. A példában egy POST metódussal egy űrlapon bevitt adatokat vizsgálunk meg, és amennyiben hiányzik az adat, akkor egy hibakezelő függvénybe irányítom át, ahol a header segítségével átirányítom egy másik oldalra, átadva neki a megfelelő változókat.

<?php
function sorry($msg,$from=1,$glob="")
{
    header("Location: sorryuser.php?from=".$from."&msg=".$msg."&glob=".$glob);
}

if(empty($name))     sorry("Hiányzik a név adat! Kötelező kitölteni",1);           

if(empty($loginname))sorry("Hiányzó login név! Kötelező kitölteni",1); 

if(empty($email))    sorry("Hiányó E-mail cím! Kötelező kitölteni. Itt kapod meg a jelszót!",1);
?>

A fenti három lehetőség közös hibája az, hogy az átirányított lapok URL-je megjelenik a böngészőben, azaz titkos információt nem tudunk átadni, továbbá azok a böngészők, amelyek nem tűrik az átirányítást, nem fognak továbbmenni.

POST metódus

A POST adatátviteli metódust az űrlapokkal kapcsolatban használhatjuk legtermészetesebben. Itt egyelőre csak annyit mondunk, hogy az ürlapok olyan HTML kódok, amelyen keresztül a böngésző előtt ülő felhasználó beírhat adatokat a HTML oldalon, az űrlap SUBMIT gombjának megnyomására pedig az űrlapon definiált mezők tartalmát, mint változóneveket és változó tartalmakat elküldi a cél oldalnak a böngésző. Az űrlap fejlécében meg kell adni a cél oldalt (kinek küldjük) és a megfelelő oldal, ha az olyan oldal, amit a szerver meg tud jeleníteni betöltődik a böngészőbe.

A PHP esetén a módszer az, hogy az űrlap kitöltése után a submit gomb megnyomásával elküldjük az eredményeket egy PHP oldalnak, amely betöltődéskor megkapja az elküldött változókat, esetleg elvégzi azokat a feladatokat, amelyekre rendeltetett, majd megjelenít valami választ.

Ennél a módszernél, az elküldött értékek nem látható módon kerülnek el a meghívott oldalhoz, tehát ezzel a módszerrel viszonylag könnyű változóértékeket átadni.

Vigyázni kell azonban arra, hogy az adatbevitel alapvetően string és ha nem úgy használjuk fel azokat a bevitt stringeket, hogy előtte kiszűrjük a ../../etc/ ... stb jellegű adatrokatés nem figyelünk arra, hogy az eredményeket a lehető legtöbb szempont szerint ellenőrizzük, akkor a web site-unk feltörhető lehet.

Az alábbi példában egy olyan HTML oldalt mutatok be, amely egy űrlapot tartalmaz, a submit gomb megnyomásának hatására az oldal önmagának (!) küldi el a változókat, majd a submit változó értéke alapján egy elágazásra kerül a végrehajtás és az eredményt elküldi e-mailben egy megadott címre. A lapon van egy kis Javascript betét is, amely az aktuális időpont beszúrására szolgál. Az űrlapon található olyan mező is, amelynek a tartalma hidden, azaz az űrlapon nem jelenik meg.

<html>
<head>
<meta http-equiv="Content-Language" content="hu">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1250">
<title>Munkalap</title>
<script language="JavaScript">
  function Kitolt()
  {
     var x=0;
     for (x=0;x<document.munkalap.lista.length;x++)
        if (document.munkalap.lista.options[x].selected) 
          document.munkalap.ceg.value = document.munkalap.lista.options[x].value;

    Alert (document.munkalap.lista.options[x].value);
}

</script>
</head>

<body bgcolor="#efefef" text="#00000000" link="#6666CC" vlink="#FF9900">

<?php 
  $datum = date('Y.M.d H:i');  //aktuális dátum
  $mikor= date ('Y.M.d');      // 

  if (!empty($pswd))               // egyszerű (primitiv) password ellenőrzés
     $jls = "_".$pswd."_";    // Lehetne biztonsáégosabban is, de itt most ez nem szempont
  else $jls = "__";

  // A munkalap elküldéséhez ki kell tölteni a partnercég nevét is.
  if(!empty($ceg))
  {
    $jel= (strpos($jls, "xxxx") == 0) | empty($munkavegzo);
    if(!$jel)
    {

    // Itt állítjuk össze az Email-t az átküldött változók értékéből.
      $uze ="";
      $uze= $uze ."Cég                   $ceg\n";
      $uze= $uze ."Bejelentő             $bejelento\n";
      $uze= $uze ."Bejelentés időpontja  $mikor\n";
      $uze= $uze ."Hibajelenség          $hibajelenség\n";
      $uze= $uze ."A hiba oka            $hibaok\n";
      $uze= $uze ."Az elvégzett munka    $elvegzett_munka\n";
      $uze= $uze ."A munkavégzés alapja\n";
      $uze= $uze ."- Garanciális         $granciális\n";
      $uze= $uze ."- Rendszergazdai      $rendszergazda\n";
      $uze= $uze ."- Fizetős             $fizetos\n";
      $uze= $uze ."- Kiszállás           $kiszallas\n";
      $uze= $uze ."- Műhelyben           $muhely\n";
      $uze= $uze ."- Rendszergazdai      $rendszergazda\n\n";
      $uze= $uze ."A szükséges munkaidő  $munkaido\n";

      if (!empty($munkadij)) {
            $uze= $uze ."Számlázott munkadíj   $munkadij Ft + 25% ÁFA\n\n";
      }

      if (!empty($alkatreszek)) {
        $uze= $uze ."Beépített alkatrészek $alkatreszek\n";
        $uze= $uze ."Alkatrészek ára       $alkatreszar Ft + 25% ÁFA\n\n";
      }

      $uze= $uze ."\n";
      $uze= $uze ."Munkavégző            $munkavegzo\n";
      $uze= $uze ."Dátum                 $datum\n";
      $uze= $uze ."Igazolás              $igazolas\n\n";
      $uze= $uze ."A munkalapot küldő gép adatai\n";
      $uze= $uze ."A gép IP címe         ".$HTTP_ENV_VARS['HTTP_HOST']."\n";
      $uze= $uze ."A gép neve            ".$HTTP_ENV_VARS['REMOTE_HOST']."\n";
      $uze= $uze ."A gépen futó böngésző ".$HTTP_USER_AGENT."\n";

      mail("europr@matavnet.hu","munkalap",$uze);

      if(  Die("Az munkalapot elküldtük!"));
   }
   if ($jel) 
      ?>
      <script language="javascript"> Alert ("Hiányosan töltötte ki a munkalapot"); </script>
     <?php
      }
     ?>

<table width="77%" border="0">
  <tr> 
    <td><font size="6" color="#6666CC"><b><img src="../jozsi_logo.png" width="100" height="93"></b></font></td>
    <td><font size="6" color="#6666CC"><b>Józsi Cégének munkalapja</b></font></td>
  </tr>
</table>

<form name="munkalap" method="post" enctype="multipart/form-data" action="index.php">
  <table width="76%" border="0">
    <tr> 
      <td width="21%"  valign="top">A partnercég:</td>
      <td width="79%"  valign="top">
        <input type="text" name="ceg" size="60">
        <select name="lista" onclick="Kitolt()">
          <option value="Nincs a listában"> </option>
          <option value="Emulátor KFT ">EKFT</option>
          <option value="Géza KFT">GKFT</option>
          <option value="Magyar-Uránusz Ujságírók Baráti Társasága">MUÚBNT</option>
          <option value="Magyar Tudományos Akadémia Ördögűző Intézete">MTAÖI</option>
          <option value="Alladin BT">ABT</option>
          <option value="Balogh Aladár SZKI">BA..KI</option>
          <option value="Kiss Piroska Irodalmi Múzeum">KPIM</option>
        </select>
      </td>
    </tr>
    <tr> 
      <td width="21%" valign="top">A bejelentő neve:</td>
      <td width="79%"  valign="top"> 
        <table border="0">
          <tr> 
            <td width="131">
              <input type="text"  name="bejelento"  cols ="60% ">
            </td>
            <td width="310">
               A bejelentés időpontja:
               <input type="text" name="mikor" value="<?php echo $mikor; ?>" >
            </td>
          </tr>
        </table>
      </td>
    </tr>
    <tr> 
      <td width="21%"  valign="top">A hibajelenség:</td>
      <td width="79%"  valign="top">
        <textarea name="hibajelenseg" rows=4 cols =60 ></textarea>
       </td>
    </tr>
    <tr> 
      <td width="21%" valign="top">A megállapított hiba</td>
      <td width="79%"  valign="top">  
        <textarea name="hibaok"  rows=5 cols =60 ></textarea>
      </td>
    </tr>
    <tr> 
      <td width="21%"  valign="top">Az elvégzett munka leírása</td>
      <td width="79%"  valign="top">
        <textarea name="elvegzett_munka"  rows="6" cols =60 >
      </textarea>
    </td>
    </tr>
    <tr> 
      <td width="21%"  valign="top"> 
        <table width="75%" border="0">
          <tr> 
            <td>Garanciális?</td>
            <td> 
              <input type="checkbox" name="garancialis" >
              </td>
          </tr>
          <tr> 
            <td>Rendszergazdai?</td>
            <td> 
              <input type="checkbox" name="rendszergazda" >
             </td>
          </tr>
          <tr> 
            <td>Fizetős?</td>
            <td> 
              <input type="checkbox" name="fizetos" >
              </td>
          </tr>
          <tr> 
            <td>Kiszállás</td>
            <td> <b> 
              <input type="checkbox" name="kiszallas" >
              </b></td>
          </tr>
          <tr> 
            <td>Műhely</td>
            <td>
              <input type="checkbox" name="muhely" >
             </td>
          </tr>
        </table>
      </td>
      <td width="79%"> 
        <p align="left">Beépített alkatrészek<br>
          <textarea name="alkatreszek" rows=2 cols =60 ></textarea>
        </p>
        <p align="left">Alkatrészek ára (nettó) 
          <input type="text" name="alkatreszar" size="40">
          +27% ÁFA</p>
      </td>
    </tr>
    <tr> 
      <td width="21%"  valign="top"><br>
        A munkát végző(k): <input type="text"  name="munkavegzo" size="30">
      </td>
      <td width="79%">Munkaórák <input type="text" name="munkaido" >
          <br>Munkadíj (netto) <input type="text" name="munkadij">+25% ÁFA
      </td>
    </tr>
    <tr> 
      <td width="21%"  valign="top"> 
        <p>Dátum: 
          <?php echo "$datum";  ?>
        </p>
      </td>
      <td width="79%"> Digitális aláírás: 
        <input type="password" name="pswd" value="titok" size=20>
      </td>
    </tr>
    <tr> 
      <td width="21%"> 
        <p>
          <input type="submit" name="Submit" value="Elküldés">
          <input type="submit" name="Reset" value="Mégsem">
         </p>
      </td>
      <td width="79%"> <font face="Times New Roman, Times, serif">Igazolás:<br>
        <textarea  name="Igazolas"  rows=2 cols =60 ></textarea>
        </font></td>
    </tr>
  </table>
</form>

<p><A HREF="index.html" onMouseOver="document.vissza.src='../visszaanim.gif';" onMouseOut="document.vissza.src='../vissza.gif'">
  <IMG SRC="../vissza.gif" NAME="vissza" ALT="Vissza a főoldalra" BORDER=0 height="25"> 
  </A> </p>
<p>Utolsó módosítás: 2011. március 12.</p>
</body>
</html>

$_SESSION változók

A session változók olyan változók, amelyek megtartják értékeiket miközben a felhasználó egyik oldalról átlép a másikra anélkül, hogy a korábban ismertetett módszerek valamelyikével direkt át kellene adnunk az értékeket a lapok között. Ez a lehetőség igazi globális változókat enged meg és sokkal összetettebb WEB-es programok készítését teszi lehetővé. Több lapból álló site fejlesztése gyakorlatilag session változók nélkül nem megy.

Amikor egy felhasználó belép egy WEB oldalra, akkor egy egyedi azonosító keletkezik, az úgynevezett session id (SID), amelyet vagy a böngészőben tárolunk úgynevezett cookie (süti) formájában, vagy a szerver oldalon tartunk nyilván. A sessionok támogatják korlátlan mennyiségű változó regisztrálását és a tartalmuk megtartását. Amikor a felhasználó eléri a web oldalt, akkor a PHP automatikusan leellenőrzi, hogy a megfelelő session id vajon már létezik-e a szerveren. Ha létezik a session id, akkor a session-höz tartozó elmentett értékeket hozzárendeli a lekért oldalhoz.

Minden oldal elején használjuk a session_start() függvényt, vagy implicit módon a session_register() függvényt.

Amikor a látogató elindít egy PHP-s lekérést, a PHP motor megnézi, hogy a fenti esetekben van-e a kéréshez hozzárendelve egy session id. Ha van, akkor a korábban elmentett környezetet hozzárendeli ehhez a kéréshez, azaz visszaállítja a megfelelő változókat. Minden regisztrált változót elment a rendszer a kérés befejeződésekor. Azok a regisztrált változók, amelyek nem kaptak értéket, azaz nem definiáltuk őket, a nem definiáltak közé kerülnek. Ezek a változók csak akkor kerülnek a definiáltak közé később is, ha a user értéket ad neki.

Ha a register_globals engedélyezett, akkor minden globális változót session változónak tudunk elmenteni, és a session változók a következő kérés során automatikusan globális változókká válnak.

Hogyan kezelhetjük a session id-ket?

  • Cookie - sütikkel
  • URL parameterekkel

A session modul mind a két változatot támogatja. A cookie-k az optimálisak, viszont vannak olyan kliensek, akik nem támogatják a cookie-k elhelyezését a gépükön biztonsági okokból, ráadásul ilyenkor a böngésző és a szerver között vándorolnak adatok is. Ez biztonsági problémákat vet fel. A második módszer esetén a session id az URL része.

A PHP képes hajlékonyan kezelni a kérdést, ha megfelelően fordítottuk. Ebben az esetben a relatív URI-k megváltoznak automatikusan és tartalmazni fogják a session ID-t (=SID). Más esetben használhatjuk a SID konstanst, amely a session_name=session_ID vagy egy üres stringet tartalmaz

(pl. PHPSESSID=8e1f5ff69434aea7ecab51da33314b53&PHPSESSID=8e1f5ff69434aea7ecab51da33314b53 )

Az alábbi példában bemutatjuk, hogyan lehet regisztrálni egy változót és egy URI-hoz hozzárendelni a session ID-t, felhasználva a SID-et.

Példa 3. Egy user  bejelentkezéseit számolja le ez a példa

<?php
session_start();
$_SESSION[”count”]++;
$count = $_SESSION[”count”];
?> 
Hello visitor, you have seen this page <? echo $count; ?> times.<p>

<php?
# the <?php echo SID; ?> is necessary to preserve the session id
# in the case that the user has disabled cookies
?>

To continue, <A HREF="nextpage.php?<?php echo SID; ?>">click here</A>

Ha a fenti kódot lefuttatjuk és megnézzük a PHP.INI-ben megadott könyvtárban lévő file-okat, akkor látni fogjuk, hogy a session indulása után létrejön egy file (pl. C:\temp-ben) valami hasonló névvel, sess_8e1f5ff69434aea7ecab51da33314b53. Ez tartalmazza a session változók nevét és értékét. Ez felveti azt a problémát, hogy az ilyen típusú file-ok a szerveren lévő temp könyvtárban csak gyűlnek és  korrekt lekezelésük idővel nagyon nehézzé válik. Azt is figyelembe kell venni, hogy egyes sessionok elévülnek, másokat nem lehet még törölni, mert éppen futó alkalmazás használja.

A PHP.INI session részében vannak azok a beállítások, amelyek a session file-ok elévülését, a szemétszedést és egyebeket szabályoznak. A szerver automatikusan gondoskodik egy idő múlva a session file-ok törléséről.

Másfelől a fejlesztőket gondoltak arra is, hogy a programozók a saját kezükbe akarják venni a session kezelésének lehetőségét. Mivel ez nem a kezdők szintjén elérhető, ezért itt nem foglalkozunk vele.

A ”sess_” kezdetű filenevek session file-okat takarnak, azoknak megnézzük és a jelenlegi időt és az utolsó hozzáférésének idejét kivonva egymásból megnézzük, hogy lejárt-e az élete.

COOKIE-k (sütik)

A cookiek használata a PHP környezetben lehetséges, de nem igazán ajánlott. A PHP alkalmazások a szerveren futnak és általában valamiféle user azonosításhoz kötöttek. A cookie-k használata esetén a cookie-ban tárolt adatok átkerülnek a böngészőt futtató számítógépre és ott egy textfile-ban tárolódnak, aminek a visszafejtése csak idő kérdése, éppen ezért fontos vagy titkolni való adatot a cookie-kba soha ne tároljunk, inkább használjunk sessionöket.

bool setcookie ( string nev, string ertek, int lejarat, string utvonal, sting domain, int titkos)

A fenti függvény minden paramétere az elsőt kivéve elhagyható. A függvényt a html oldal headerében kell elküldeni, mielőtt az oldalra bármit kiírnánk! Az alábbi példában elküldünk egy egyszerű értéket:

ParamLeírásPélda
NevA süti neve'teszt’ nevű változót hozzuk létre $_COOKIE['teszt']
ErtekEz az érték tárolódik a kliens oldalonEzt az értéket tároljuk a 'teszt' nevű változóban. $ertek =$_COOKIE['teszt']
LejaratA süti lejárati ideje másod-percekben megadva. Beállítása time() + lejárati idő.time()+60*60*24*2 két napot állítunk be lejáratnak. Ha nincs beállítva, akkor aböngésző bezárásáig érvényes a süti.
UtvonalHol tároljuk a sütiket.Minden böngédsző rendelkezik egy alapértelmezett süti tárhellyel. Beállíthatjuk, hogy ehhez képest hol tárolja a sütiket. Például a /fz/ az fz alkönyvtárba teszi a sütiket.
DomainAz a domain, amire érvényes a sütiItt adhatjuk meg, hogy melyik aldomainre legyen érvényes a süti. A www.fz.ini.hu esetén csak erre a domainre érvényes.
TitkosHa az érték 1, akkor csak HTTPS esetén küldi sütit.0 vagy 1 , alapérterlmezés 0
<?php
$ertek = 'Ez itt a példaszöveg';
setcookie ("teszt", $ertek);
setcookie ("teszt", $ertek,time()+3600);  /* egy óra múlva jár le a süti */
setcookie ("teszt", $ertek,time()+3600, "/fz/", ".fz.ini.hu", 1);
/* Az /fz alkönyvtárban, a www.fz.ini.hu domain és https protokoll esetén */
?>

Tömböket is tárolhatunk sütikben.

<?php
// A sütik beállítása
setcookie ("cookie[three]", "cookiethree");
setcookie ("cookie[two]", "cookietwo");
setcookie ("cookie[one]", "cookieone");
 
// A következő oldalon betöltve az alábbi kóddal irathatjuk ki az adatokat:
if (isset($_COOKIE['cookie'])) {
    foreach ($_COOKIE['cookie'] as $name => $value) {
        echo "$name : $value <br />\n";
    }
}

/* Ez lesz az eredmény
three : cookiethree
two : cookietwo
one : cookieone
*/
?>

A következő oldalt betöltve a böngészőbe a sütik automatikusan megjelennek a $_COOKIE tömbben, és azokat az értékeket lehet használni. Ha a register_globals paramétert bekapcsoljuk a php.ini-ben, akkor automatikusan létrejönnek a megfelelő változók, de korábban említettük, hogy ennek a paraméternek a bekapcsolása nem javallott.

Ha a $_COOKIE tömb értékeit debuggolás céljából ki akarjuk iratni, akkor használjuk a következő utasítást:

<?php
print_r( $_COOKIE );
?>