9.16. Fájl kezelés

Default book

Az alábbi fejezetben megnézzük, hogy melyek a leggyakrabban használt függvények és módszerek a PHP programokban. Amennyiben valaki úgy vélné, hogy más függvények gyakrabban használatosak az ő programjaiban, nagyon sajnálom, a help alapján kell megnézni a működésüket – sokszor én is ott nézem meg.

Az alábbi esetek fordulnak elő a file kezelésnél leggyakrabban a PHP programok esetén:

  • Távoli szerverről szeretnénk olvasni, vagy távoli szerverre írni
  • Helyi könyvtárszerkezetből szeretnénk olvasni, vagy ide szeretnénk írni. Az írásnál előfordulhat, hogy a kimenetet a helyi standard outputra szeretnénk tenni.
  • A fenti eseményeket bináris vagy text file esetén is meg akarjuk valósítani.
  • Helyi és távoli gépen is szeretnénk könyvtárakat létrehozni, vagy könyvtárakat törölni.
  • Alkalmanként kell vizsgálnunk, hogy a kérdéses file a helyi filestruktúrában vagy távoli szerveren létezik-e?
  • Egy megadott elérési útvonal file-ra, könyvtárra vagy link-re mutat-e?
  • A fileok kezeléséhez jó, ha tudjuk az alábbiakat:
    • Az éppen aktuálisan futó alkalmazás lokális szerveren lévő elérési útvonalát a
      • $_SERVER[”PATH_TRANSLATED”] stringváltozó tartalmazza
    • A WEB szerver gyökérkönyvtárát a
      • $_SERVER[”SERVER_ROOT”] változó tartalmazza
    • Az operációs rendszer temporary könyvtárát
      • a $_ENV[”TEMP”] vagy hasonló nevű szuperglobális változó tartalmazza.

A file kezelésnél tudnunk kell, hogy az otthoni környezetben futtatott program eléri-e az éles szerveren is ugyanazt a könyvtárat. Ha egy web struktúrában lévő file-t kell elérnünk, akkor célszerű kiindulnunk az éppen futó alkalmazás könyvtárából. A fentiek alapján, ha az index.php alkalmazásunk az alábbi helyen fut:

C:\wwwroot\valami

És egy geza nevű alkönyvtárban lévő szoveg.txt file-ra szeretnénk hivatkozni, akkor az alábbi elérést kell alkalmazni:

$el = $_SERVER[”PATH_TRANSLATED”].”/geza/szoveg.txt”;

Az elérési útvonalak kezelése során gyakori, hogy szét kell választanom az elérési utat könyvtár, filenév illetve kiterjesztés részre. Az alábbi függvények a fenti elérési utat választják szét:

$path = ”C:/wwwroot/valami/geza/szoveg.txt”;
$file = basename ($path);         // $file értéke "szoveg.txt"
$file = basename ($path,".txt"); // $file értéke "szoveg", mivel a második paraméter hatására 
                                                // a végéről levágja a megadott stringet.
$dir  = dirname ($path);           // $d értéke ”C:\wwwroot\valami\geza" lesz.

Alternatív megoldás a fenti feladatra lehet a pathinfo függvény:

<?php

    $path_parts = pathinfo("/www/htdocs/index.html");
    echo $path_parts["dirname"] . "\n";
    echo $path_parts["basename"] . "\n";
    echo $path_parts["extension"] . "\n";
?>
boolean is_dir($path);  //Könyvtár?
boolean is_file($path); //Fájl?
boolean is_link($path); //Csak egy link?

Egy file további tulajdonságait – attribútumait az alábbi függvényekkel kaphatjuk meg:

int is_executable($path ) - Megmondja, hogy a bejegyzés futtatható-e. Ez Windowson és Linuxon kicsit más lesz.

int is_readable($filename) – Megmondja, hogy a file olvasható-e

int is_writeable($filename) – Megmondja, hogy a file írható-e.

int fileatime ($filename) - A file utolsó elérési ideje. A visszaadott idő UNIX időbélyeg formájában.

int filemtime($filename) – A file utolsó módosításának ideje Unix időbélyeg formájában.

int fileowner($filename) – A file tulajdonosának ID-je. Csak lokális filerendszerben használható.

int fileperms($filename) – A filera vonatkozó jogokat adja vissza. Csak lokális filerendszerben használható.

int filesize($filename) - a file mérete

<?php

$filename = ”C:/wwwroot/valami/geza/szoveg.txt”;
echo filesize($filename);
?>

A filekezelés meglehetősen hasonlít a C-ben megszokottakra:

Egy file olvasása előtt meg kell nyitnunk azt. Erre a célra az

$fp = fopen($filenev, mód)

függvényt használhatjuk, ahol a $filenév egy lokális filerendszer egy file-ja vagy egy URL-lel megadott file lehet. Ha Windows rendszert használunk, akkor a filenévben az elérési útban szereplő könyvtárneveket a \\ jellel kell elválasztani, de használhatjuk a / jelet is. Sőt, ha Windowson fejlesztünk, majd Linuxon futtatjuk a kódot, akkor érdemes az alábbit megvalósítani:

$fname = "C:\\wwwroot\\index.html";

$fname = str_replace("\\","/",$fname);

$fp=fopen ($fname,”w”);

Ha a $filenév a http:// vagy az ftp:// jelekkel kezdődik, akkor egy távoli szerveren lévő file-ról van szó.

$fp = fopen(”http://www.szily.hu/index.html”,”r”);

A file megnyitásának módja az alábbi lehet:

módleírásPélda
’r’Olvasásra nyitom meg a file-t. File pointer a file elején áll
$fp = fopen(”C:\\autoexec.bat”,”r”)
’w’Írásra nyitom meg a file-t. A file pointer a file elejére áll és ha volt ilyen file, akkor megsemmisül, zéró hosszúságúvá válik
$fp = fopen(”C:\\inetpub\\default.htm”,”w”)
'r+'Írásra és olvasásra nyitom meg a file-t. A pointer a file elejére áll.
$fp=fopen(”C:\\inetpub\\adat.ini”,”r+”)
’w+’Írásra és olvasásra nyitom meg a file-t. A pointer a file elejére áll. A file megnyitáskor 0 hosszúságúra csonkolódik
$fp=fopen(”C:\\inetpub\\adat.ini”,”w+”)
'a'Írásra nyitom meg a file-t. A pointer a file végére áll.
$fp=fopen(”C:\\inetpub\\adat.ini”,”a”)
’a+’Írásra és olvasásra nyitom meg a file-t. A pointer a file végére áll.
$fp=fopen(”C:\\inetpub\\adat.ini”,”a+”)
’b’Ha biztosan bináris file-t akarok olvasni vagy írni, akkor a megnyitáskor a mód stringbe be kell írni ezt is.
$fp=fopen(”C:\\autoexec.bat”,”rb”)

A fenti utasítás hibaüzenetet ad, ha nem létezik az olvasásra megnyitni akart file. Ezért a hibakezeléshez az alábbiakat kell tenni:

if (file_exists($fname))                    // Létezik a file?    
{
  $fp = fopen($File,"r");            
  // Megnyitjuk olvasásra
}

Mielőtt olvasni szeretnénk egy file-t, meg kell nézni, hogy létezik-e. A létezés ellenőrzésére a

if(file_exists($filename) ){
  echo "A file létezik"
}

függvényt használhatjuk. A visszatérési értéke igaz, ha a file létezik, hamis egyébként.

Ha az fopen-nel megnyitottunk egy filet írásra olvasni akarunk fájlokat, akkor az alábbi függvényeket használhatjuk

$c = fgetch($fp);    // Egy karakter beolvasása

$sor = fgets($fp,sorhossz);       //Egy sor beolvasása a fájlból

A sorhossz paraméter nem kötelező, ha nem tesszük ki, akkor alapértéke 1024 karaktert olvas a függvény.

Ha az fopen-nel megnyitottunk egy file-t írásra és, ki akarom szedni a beolvasott file-ból az esetlegesen benne lévő html tag-okat, akkor ezt kell használni.

$sor= fgetss($fp,sorhossz);

Ha nem adjuk meg a sorhosszat, akkor max 1024 hosszú stringet olvas be.

Ha egy text file összes sorát be akarjuk olvasni egy tömbbe, akkor az alábbi függvényt kell használni:

$aline = file($filename);

A függvény beolvassa a megadott $Filename elérési útvonalú text file sorait egy $aline nevű tömbbe. A függvénnyel nemcsak a lokális file rendszerből, hanem URL-lel megadott file-ból is lehet olvasni! Ha a file nem létezik, akkor hibaüzenet keletkezik, és a tömb elemszáma 0 marad. A kezelésére nézzük az alábbi példát a Help alapján:

<?php

// A beolvasandó file egy URL-lel van megadva.
$filename =”http://www.szily.hu/szily/szily.css”;
$asor = @file($filename);
if(count($asor==0)){
    die(”Nem létező file”);
}

// A beolvasott file feldolgozása és a sorok kiiratása. 
// A html sorokat kiírja, mint html szöveg, sor és sorszámot is kiír.
foreach ($asor as $line_num => $sor) {
    echo "#<b>{$line_num}</b> sor : " . htmlspecialchars($sor) . "<br>\n";
}

// Ez a példa egy file-t beolvas, majd a sorokat egy stringgé összevonja.
$html = implode ('', file ('http://www.szily.hu/szily/'));
?>

Ha egy teljes file-t akarunk beolvasni, akkor az alábbi függvényt lehet használnunk:

$t = fread($fp,$filesize( $filenev));

A filesize($filenev) függvény megadja az adott file méretét byte-okban és a paraméter hatására a file méretnek megfelelő puffert foglal le a memóriában a PHP. A visszatérési érték változója tartalmazza majd a file összes byte-ját, mint string. Ez a függvény bináris olvasáskor használható igazán, mert a beolvasott tartalommal semmiféle konverzió nem történik.

Egy írásra vagy írásra/olvasásra megnyitott fileokba való írásnál alapvető függvény az

int fwrite($fp,$c);

Ha a kiírandó érték egy karakter, akkor karakterenként írunk, ha egy textfile egy sora, akkor a sorvége jelet hozzá kell tennünk a kiírandó tartalomhoz az alábbi módon:

$c = $sor.”\r\n”;

Ha egy file tartalmát akarjuk kiiratni, akkor a változó tartalmazza a teljes tartalmat.

Nem túl nagy méretű fájlok tartalmának a beolvasásához használhatjuk

$str = file_get_contents($filename);

Ez a függvény egyben beolvassa egy fájl tartalmát binárisan és elhelyezi a megadott stringbe. A beolvasott fájl méretkorlátja a rendelkezésre álló memória. Például egy mp4 fájlt ne akarjuk ilyen módon beolvasni, de egy képnek az adatait nyugodtan (2-14 MB) attól függően, hogy a PHP-nek mennyi memória áll rendelkezésére.

Ha egy string tartalmát akarjuk egy az egyben kiírni egy fájlba, akkor pedig ezt kell használnunk:

$size = file_put_contents($filename, $str [, $flag]);

A megadott fájlba beleírjuk a $str string tartalmát. A memória mérete korlátozza az utasítás használatát, illetve az, hogy az adott pillanatban összeállt-e minden szükséges adat az íráshoz.

A $flag az alábbi lehet:

FILE_USE_INCLUDE_PATHinclude könyvtárban is kereshetjük a file-t.
FILE_APPENDHa a file létezik, akkor hozzáírja a tartalmat és nem felülírja a fájlt.
LOCK_EXMás folyamatok számára lezárja a fájlt, amíg az írási folyamat zajlik. Erre akkor lehet szükség, ha nagy méretű fájlt írunk és sokáig tart az írási folyamat.

Álljon itt filekezelésre egy komplexebb példa. Egy file-ból olvasnom kell, de ehhez először meg kell nyitnom.

<!-
Ez a program megvalósít egy egyszerű karakter alapú számlálót. A számláló
pillanatnyi  értéke  a counter.txt  állományban van, amit a szkript beolvas
értékét minden egyes beolvasás során megnöveli, a megnövelt értéket ugyan-
abba a fileba visszaírja, majd a számláló állását megjeleníti. Ahhoz, hogy
program megfelelően működjön a counter.txt állományt létre kell hoznunk,
melynek tartalma csak '1' legyen, ezt a fájlt fel kell töltenünk ugyanabba
a könyvtárba, ahol a program van, és írási jogosultságot kell adnunk rá.
-->

<hr>

Látogatók száma:<BR>

<?php
    $File = 'counter.txt';     // A számláló file neve
    if (file_exists($File))    // Létezik a file?
    {
        $fp = fopen($File,"r");              // Megnyitjuk olvasásra
        $num = fread($fp, filesize($File));  // Beolvassuk a tartalmát a $num változóba.
        fclose($fp);                         // Zárjuk a filet.
        $num=$num+1;                         // A változó értékét megnöveljük
        $fp = fopen($File,"w");              // Megnyitjuk ugyanazt a filet, de most írásra
        fwrite($fp, $num, 10);               // Kiírjuk a változó értékét.
        fclose($fp);                         // Zárjuk a fájlt
        echo('<b>'.chop($num).'</b>');       // Kiírjuk a HTML-kódba a változó értékét.
    }
?>
<hr>

Az alábbi komplex példa egy működő program része. A program a paraméterben megadott szerveren lévő fájlt megnyitja, majd kiküldi a böngészőnek.Természetesen ellenőrzéseket kell végezni, majd mivel a fájl tetszőlegesen nagy lehet, egy méret alatt egyben olvassuk be a fájl tartalmát és küldjük ki, ha pedig egy nagy fájlról (például egy filmről van szó) akkor egy ciklussal kell kiolvasni és kiküldeni a böngészőnek az eredményt. A program több egyéb ellenőrzést is elvégez. A fájlnak az aktuális könyvtárban kell ennie. Ha a fájl kép, vagy bináris tartalom, akkor a böngészőnek megfelelő típusú fejlécet kell küldeni, hogy tudja, hogy milyen módon kezelje az információt.

<?php
/* $Id: image.php,v 1.15.2.3.2.2.2.11 2009/10/29 00:09:17 tjfulopp Exp $ */

/* Check for bad URL inputs */
include "inc/functions.inc";
$url = isset($_GET['i']) ? $_GET['i'] : "/";

if( strpos($url, "://") !== false || strpos($url, "..") !== false ) {
 	header("HTTP/1.0 404 Not Found");
 	exit();
}

$root= __DIR__."/image";

$tmp = realpath($root.$url);
if(is_dir($tmp ) || !file_exists($tmp)){
  $root= __DIR__."/image";
  $url       ="/404.png";
}
$root = str_replace("\\","/",$root);

$path      = pathinfo($url, PATHINFO_DIRNAME);
$name      = pathinfo($url, PATHINFO_BASENAME);
$ext       = pathinfo($url, PATHINFO_EXTENSION);

//headers
$head     = _smpl_get_image_head($ext);
$size     = filesize($root.$url);
$filename = basename($url);
header("Cache-Control:max-age");
header("Content-disposition: inline; filename=".$filename );
header("Content-length: ".$size);
header($head);

$bufferlength = 4000000;
if($size<$bufferlength){
  echo file_get_contents($root.$url);
}else{
  $buf ='';
  $f = @fopen($root.$url,'rb');

  if($f){
	 $content ='';
	 while ( $content = @fread($f,$bufferlength) ) {
		  echo $content;
	 }
	 @fclose($f);
  }
die();
}

/**
 * Read data of a picture file
 */
function _smpl_get_image_head($ext){
	$ext = strtolower($ext);
  switch ($ext){
  	//Image mime types
  	case 'jpg':
    case 'jpeg':
    case 'tmp':
    	$type= 'image/jpeg';
    	break;
   	case 'gif':
   		$type= 'image/gif';
   		break;
   	case 'png':
   		$type= 'image/png';
   		break;
   	case 'bmp':
   		$type= 'image/bmp';
   		break;
   	case 'wbmp':
   		$type= 'image/wbmp';
   		break;
   	case 'wbmp':
   		$type= 'image/wbmp';
   		break;
   		//Audio mime types
   	case 'mp3':
   		$type= 'audio/mpeg';
   		break;
    case 'flac':
   			$type= 'audio/flac';
   			break;
   	case 'ogg':
   			$type= 'audio/ogg';
   			break;
		case 'kar':
   	case 'rmi':
   	case 'mid':
   		$type= 'audio/mid';
   		break;
   	case 'wav':
   		$type= 'audio/x-wav';
   		break;
   	case 'ra':
   		$type= 'audio/x-pn-realaudio';
   		break;
    //Video mime types
    case 'avi':
   		$type= 'video/x-msvideo';
   		break;
   		case 'wmv':
   			$type= 'video/x-ms-wmv';
   			break;
    case 'flv' :
   		$type= 'video/x-flv';
   		break;
    case 'mov' :		//QiuickTime
   		$type = 'video/quicktime';
   		break;
    case '3gp' :		//Mobil
   			$type = 'video/3gpp';
   			break;
    case 'mpg' :
    case 'mp2' :
    case 'mpe' :
    case 'mpeg':
    case 'mpv2':
   		$type = 'video/mpeg';
   		break;
   	case 'mp4':
   		$type = 'video/mp4';
   		break;

   	case 'm3u8': 		//iPhone
   			$type= 'application/x-mpegURL';
   			break;
   	case 'ts';		//iPhone
   		$type= 'video/MP2T';
   		break;
   	//Documents mime types
		case 'doc':
   		$type= 'application/msword';
   		break;
   	case 'docx':
   		$type= 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
   		break;
   	case 'xlsx':
   			$type= 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
   			break;
  	case 'xls':
   			$type= 'application/vnd.ms-excel';
   			break;
		case 'pps':
		case 'ppt' :
				$type = 'application/vnd.ms-powerpoint';
			break;
		case 'ppsx':
			$type= 'application/vnd.openxmlformats-officedocument.presentationml.slideshow';
			break;
		case 'pptx':
   		$type= 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
   		break;
   	case 'pdf':
   		$type='application/pdf';
   		break;
   	default:
   		$type = 'application/data';
  }
	return "Content-type: ".$type;
}