PHP.ee
 php.ee   linuxator.com   whee 
07.02.12 / 23:25
  Artiklid
  » Algajaile
  » Andmebaasid
  » Varia
  » Graafika
  » Advanced
Logi sisse:
< nimi
< pass
Unustasid passi?
Kas eelistad võimalusel PHP koodi objektorienteeritult kirjutada?
 Jah, see teeb töö lihtsamaks
 Jah, see on lihtsalt lahe
 Nii ja naa, ei tunne erilist võitu
 Ei, mõttetu ajakulu
 Ei oska objektorienteeritult progeda
Tulemused
Liitu listiga!
Telli PHP uudiskiri
Nimi:
Email
Tekstipõhist külalisteraamatut lahkamas
Kilukarp

Antud kood eeldab, et php.ini failis on register_globals sisselülitatud

Tuli mõte kirjutada tekstipõhine külalisteraamat.
Järgnevalt lahkakski mida ja kuidas ma tegin.

Kogu kood on jagatud mitme erineva faili vahel:
config.inc - algväärtused
kaunter.inc - loenduri funktsioonid
index.php - põhifail
admin.php - administreerimine st. muutmise/ kustutamise frontend
lisa.php - lisamine
muuda.php - muutmine
kustuta.php - kustutamine


Alustaks millestki lihtsast - näiteks kirje lisamine

Väike päringu lähtekoha kontroll - see on vajalik, sest osad proxy-d korhavad õige HTTP_REFERER-i ära asendades selle näiteks päritava aadressiga. Tulemuseks on skript, mis püüab paaniliselt iseendaga suhelda. Sõltuvalt serveri kiirusest liigutatakse enne skripti timeout-i tohutu kogus infot - mul näiteks paari sellise päringu tulemusel mõned Mb-d ;-)
Kontrollin esitaks, kas HTTP_REFERER ikka täidetud ja ega skripti enda nime HTTP_REFERER-is ei ole.

if ( empty($HTTP_REFERER) or strpos( $HTTP_REFERER, $PHP_SELF )) {
$next_leht = "index.php";
} else {
$next_leht = $HTTP_REFERER;
}

Et hilisem veakontroll mingeid kahtlaseid tulemusi ei saaks, annan vea loendurile algväärtuse.

$my_error = 0;

Andmete struktuur (kirje) on kr-is lihtne: 5 elementi, loendamine algab 0-st. Sellise lihtsa ja tühja kirje ka siin kirjeldan

$my_rida = array( 0 => '', '', '', '', '');

Need andmed tuleks millegiga täita. Selleks sobivad teisel lehel asunud formi elemendid. Kuna ma ei viitsi neid kõiki ükshaaval kontrollida, siis mõtlesin välja kontrolli läbi massiivi (kirjeldus asub config.inc)

Sissetulnud andmete kontroll
Tsüklis massiivi (array) elementide läbijalutamiseks on PHP4-s välja mõeldud funktsioon foreach

foreach( $formi_sisu as $key => $value ) {

PHP3-e kasutajad saavad samasuguse tulemuse reaga;

reset( $formi_sisu);
while ( list( $key, $value) = each ($formi_sisu)) {

Sissetuleva muutuja nimi

$vali = $value['vali'];

Kontrollin, kas vastava nimega muutuja on olemas ja kas see sisaldab ka mingitki infot.

if( isset( $$vali) and !empty( $$vali)) {

$$ on selline kaval konstruktsioon, et muutuja sisu saab käsitleda nagu see oleks muutuja nimi:
$kala = 5 => echo $kala => tulemuseks '5'
$kilu = 'kala' => echo $kilu => tulemuseks 'kala'
echo $$kilu => tulemuseks '5'


Kui muutuja on olemas, siis panen muutuja massiivi

$my_rida[$key] = $$vali;
} else if( $value['ok'] == 1 ) {

Kui muutujat ei ole olemas, samas on mul märgitud, et peab olema ('ok' => 1)
Võtan kirjeldusest veateate ja lisan selle teadete vektorisse. Ühtlasi liidan, vealoendurile ühe juurde.

$message[$key] = $value['viga'];
$my_error += 1;
} else {

Kui muutujat ei ole olemas ja selle kohta on ka märge, et pole ka vaja ('ok' => 0). lisan kirjele tühja välja.
Alguses mõtlesin, et miks seda üldse vaja on - kustutaks järgmise rea ära, sest kirje sai juba oma algväärtuse kätte. Siis mõtlesin, et olen piisavalt laisk ja ei viitsi hiljem kogu koodi läbi nämmutada. Kirje kriitiline pool on kirjeldatud aga kui ma lisan uusi elemente kirje lõppu. Piisab ainult config.inc-is kirjelduste muutmisest. Lisatud elementide algväärtus pannakse siin paika.

$my_rida[$key] = '';
} // if
} // foreach


Vigane kirje
Kui kirje on üle vaadatud, kontrollin vigade olemasolu

if ( $my_error > 0 ) {

Näib, et leidus vigu, muidu siia ei satuks
Registreerin kõik formi elemendid sessiooni muutujateks. See on vajalik, sest ma sellel lehel ei kavatse midagi välja trükkida, vaid anna töö eelmisele lehele tagasi.
Samas ei pea sisestaja mingeid andmeid uuesti sisestama.
See on nüüd koht, mis zones kindlasti tööle ei hakka. Kogu selle asja asemel tuleks kasutada mingit veateadet sellel lehel ja siis javaskriptiga history(-1) .

foreach( $formi_sisu as $key => $value ) {
session_register( $value['vali'] );
} // foreach

Registreerin ka veateate(d)

session_register( 'message' );

Ja lähen tagasi lehele, mis mulle selle vigase formi kaela määris - $next_leht näitab teed ;-)

header( "Location: $next_leht?alates=$alates#kala" );
exit;

Vigase kirje korral siin ka töö lõppeb

} // if


Korras kirje
Kuna vigu ei leitud jätkan siit.
Kõigepealt mõned puuduvad kirje elemendid
Tänane kuupäev ja kell kujul YYYYmmddHHiiss

$my_rida[kuupaev] = date('YmdHis');

Järgmiseks võtan kirje postitaja aadressi

$my_rida[ip] = $HTTP_SERVER_VARS["REMOTE_ADDR"];

NB! See võib olla ka postitaja cache aadress, mitte masina oma. Minul ei puhu selline täpsus pilli, samas kui kedagi segab kasutagu järgmist rida:

if (getenv(HTTP_X_FORWARDED_FOR)){
$my_rida[ip]=getenv(HTTP_X_FORWARDED_FOR);
} else {
$my_rida[ip]=getenv(REMOTE_ADDR);
}

HTTP_X_FORWARDED_FOR võib koosneda mitmest aadressist, mis on komaga eraldatud
HTTP_X_FORWARDED_FOR-i võib iga kasutaja ka ise defineerida, seega ei ole selle vastus 100% kindel!
Kindlasti ära kasuta seda mingi audentimise juures!

Väike töötlus sisestatud tekstile. See on vajalik, sest kirje peab asuma ühel real ja ei tohi sisaldada "|" märki, sest see on kirje elementide eraldamiseks    

$pat="((rn)+|(nr)+|n+)";
$repl='<br>';
foreach( $my_rida as $key => $value ) {
$my_rida[$key] = str_replace( '|', '&brvbar;', ereg_replace($pat, $repl, htmlentities( trim( $value ))));
} // foreach

trim() - korjab ära alguses ja lõpus olevad tühikud ning muud märgid, mis ei jäta printimisel jälgi.
htmlentities() - teisendab kõik vähegi sobiva htmlentites-iks (ei leidnud eesti keelset vastet)
ereg_replace() - sellisel kujul, nagu ta mul on korjab ära kõik reavahetused ja asendab need <br> tagiga
str_replace - asendab "|" html-i märgiga "&brvbar;"

Liidan saadud tulemuse kokku üheks pikaks stringiks, kasutades eraldajaks "|" märki ja lõppu panen reavahetuse.

$kiri = join( '|', $my_rida )."n";


Faili lisamine
Avan faili
a - võti viib kirjutamise pointeri kohe lõppu
b - võti kirjutab binaarselt sobiva koodi

$fp = fopen( $failinimi, 'ab');

Kontrollin, kas avamine õnnestus, ühtlasi lukustan faili kirjutamiseks
NB! Kui ei lukustaks, ootaks peagi ees isetühjenenud külalisteraamat ;-)

if ($fp !=0 && flock($fp,2)){

Kirjutan rea faili

$kala = fwrite( $fp, $kiri, strlen($kiri));
} // if

Sulgen faili

fclose( $fp );

Lisan loendurisse uue numbri - sellest põgusalt hiljem. Põhiidee on toodud ära "Kaunteri lahkamine" nimelises teoses

add_counter( 'count_ins.txt' );

Ja lähen tagasi lehele, mis mulle selle portsu kaela määris - $next_leht näitab teed ;-)

header( "Location: $next_leht?alates=$alates#kala" );
exit;

#


Konfiguratsioon - config.inc

Külalisteraamatu faili nimi

$failinimi = 'jutud.txt';

Ridade arv ekraanil ehk lehekülje suurus

$maxridu = 5;

Kirjeldan konstandid, et oleks mugav andmeid käsitleda - ei pea mõtlema väljade paiknemisele

define( 'kuupaev', 0 );
define( 'ip' , 1 );
define( 'nimi' , 2 );
define( 'epost' , 3 );
define( 'sisu' , 4 );

Formi töötluse jaoks vajalik massiiv. Massiiv on siis kahemõõtmeline esimene mõõde jookseb siis piki eelpool mainitud konstante (nimi, epost jne)
Teistpidi jooksevad elemendi kirjeldused:
vali - kirjeldab formilt saadud muutuja nimetust
viga - kirjeldab vea ilmnemisel veateadet.
ok - kirjaldab, kas väli on kohustuslik(1) või ei ole(0)

$formi_sisu = array(

nimi => array(
'vali' => 'f_nimi',
'viga' => 'Nimi on puudu!',
'ok' => 1 ),

epost => array(
'vali' => 'f_epost',
'viga' => '',
'ok' => 0 ),

sisu => array(
'vali' => 'f_sisu',
'viga' => 'Sisu on puudu!',
'ok' => 1 )

);

Sama kirjeldus administratiiv-mooduli jaoks, kus saab olemasolevaid andmeid muuta

$formi_admin = array(

ip => array(
'vali'    => 'f_ip',
'viga'    => 'IP on puudu!',
'ok'    => 1 ),

nimi => array(
'vali'    => 'f_nimi',
'viga'    => 'Nimi on puudu!',
'ok'    => 1 ),

epost => array(
'vali'    => 'f_epost',
'viga'    => '',
'ok'    => 0 ),

sisu => array(
'vali'    => 'f_sisu',
'viga'    => 'Sisu on puudu!',
'ok'    => 1 )
);

Juhul kui lehitsemise muutuja on kirjeldamata annan sellele algväärtuse

if( !isset( $alates)) $alates = 0;

#


Loenduri fail - kaunter.inc

Kuna sellel teemal on olemas eraldi artikkel "Tekstikaunterit lahkamas" siis siinkohal mainin ainult, et tegin asjast kaks käepärast funktsiooni

Esimene lisab loenduri ja tagastab selle uue väärtuse

function add_counter( $failinimi = '' )

Teine küsib kindlalt loendurilt selle väärtust

function get_counter( $failinimi = '' )

#


Kirje kustutamine – kustuta.php

Vaataks kuidas kustutada kirjet
Kõigepealt kontrollin, kas midagi üldse sooviti kustutada. Kui ei soovitud saadan järje tagasi admin.php nimelisele lehele

if ( !isset( $kiri ) or empty( $kiri )) {
header( "Location: admin.php?alates=$alates" );
exit;
}

Järgmiseks avan külalisteraamatu faili ja kontrollin, kas avamine ja lukustamine õnnestus. Lukustamine on vajalik, et vältida faili tühjenemist kui mitu protsessi korraga tahavad faili muuta.

$fp1 = fopen( $failinimi, 'rb');
if ($fp1 !=0 && flock($fp1,2)){

Kui avamine ja lukustamine õnnestus, küsin süsteemilt ilusa ja unikaalse failinime. Avan ajutise faili ning lukustan selle. Ajutist faili on vaja, sest failist rea kustutamine on tegelikult reale eelnevate ja järgnevate ridade uude faili kopeerimine.
Kui ikka kirjeid on väga palju ja selline majandamine saab pidurdavaks, tasub mõelda kustutatava kirje algusesse mingi kindla märgi panekust tähendusega, et see kirje on kustutatud ja hiljem mingil süsteemi jaoks vabamal hetkel tuleks need kirjed failist eemaldada.

$tempname = tempnam( './', 'TMP');
$fp2 = fopen( $tempname, 'wb');
if ($fp2 !=0 && flock($fp2,2)){

Järgmiseks käin reakaupa kogu külalisteraamatu läbi. Juhul kui rida ei ole tühi või rea number ei võrdu kustutamisele määratud reaga, kirjutan rea ajutisse faili.

while (!feof ($fp1)) {
$my_counter += 1;
$kirjad = trim(@fgets( $fp1, 4096));
if (($my_counter == 1 ) or ( $kiri != $my_counter) and !empty( $kirjad )) {
fwrite( $fp2, $kirjad."n" );
}
}

Sulgen külalisteraamatu ja ajutise faili.

}
fclose( $fp2 );
}
fclose( $fp1 );

Kustutan külalisteraamatu ja nimetan ajutise faili ümber külalisteraamatuks.

unlink( $failinimi );
rename( $tempname, $failinimi );

Tagasi adminni lehele

header( "Location: admin.php?alates=$alates" );

#


Kirje muutmine – muuda.php

Kirje muutmine on tegelikult kombinatsioon uue lisamisest ja kustutamisest.
Seega mujal pikemalt ei peatu kui ainult muutmise tsüklil.
Käin reakaupa kogu külalisteraamatu läbi. Juhul kui rida ei ole tühi või rea number ei võrdu muutmisele määratud reaga, kirjutan rea ajutisse faili. Kui rea number on sama muutmisele mineva reaga, kirjutan selle rea asemele uue rea.

while (!feof ($fp1)) {
$my_counter += 1;
$kirjad = trim(@fgets( $fp1, 4096));
if (( $f_id != $my_counter ) and !empty( $kirjad )) {
fwrite( $fp2, $kirjad."n" );
} else if ( $f_id == $my_counter ) {
    fwrite( $fp2, $kiri."n" );
}
}

#


Külalisteraamat – index.php

Külalisteraamat saab aru järgmistest GET parameetritest:
alates= lehekülg – mitmendat lehekülge näidatakse.
tsitaat=kirje – mitmendat kirjet tsiteeritakse

Et saada tegelik alguskirje number korrutan lehekülje numbri kirjete arvuga leheküljel

$alates1 = $alates* $maxridu;

Külalisteraamatu form saada andmed lehele lisa.php – selline loksutamine on hea, sest pärast leheküljel refreshi vajutades ei küsita rumalaid küsimusi uuesti postituse kohta. Et sattuda pärast tagasi samale leheküljele, annan edasi ka lehekülje numbri.

<form method="post" action="lisa.php">
<input type="hidden" name="alates" value="<?=$alates?>">

Initsialiseerin 2 loendurit ja avan faili. Ühte loendurit läheb vaja, et pidada arvet failist loetud ridade kohta, teist kasutan väljatrüki loendamiseks

$my_counter = 0;
$my_ocounter = 0;
$fp = @fopen ( $failinimi, "r");

Loen failist reakaupa, kuni sealt midagi saab lugeda, samas suurendan loendurit

while ( !feof( $fp )) {
$my_counter += 1;
$kirjad = trim( @fgets( $fp, 4096 ));

Kui rida on tühi, siis seda ei näita.

if ( !empty( $kirjad )) {

Kui rida mahub vajaliku lehekülje raamidesse, siis läheb kirje töötlusesse

if (( $my_counter> $alates1 ) and ( $my_ocounter < $maxridu )) {

Kõigepealt eraldan rea kirjeteks. Siin kasutan kirjete eraldamiseks märki “|”

$kiri = explode( "|", $kirjad );

Külalisteraamatus olev kuupäev on samal kujul, nagi timestamp mysql-is.
Neli kohta aastale + 2 kohta kuule + 2 kohta päevale + 2 kohta tunnile + 2 kohta minutile + 2 kohta sekundile ehk siis yyyymmddhhmmss
Et saada sellest kõigile mõistetavat kuupäeva, pean teostama väikese stringitöötluse

$kuupaev = substr( $kiri[kuupaev], 6, 2 ).'.'.substr( $kiri[kuupaev], 4, 2 ).'.'.substr( $kiri[kuupaev], 0, 4 ).' '.substr( $kiri[kuupaev], 8, 2 ).':'.substr( $kiri[kuupaev], 10, 2 ).'.'.substr( $kiri[kuupaev], 12, 2 );

Kui epost on antud, lisan selle lingi nimele, vastasel juhul ainult nimi

if( !empty( $kiri[epost])) {
$nimi = '<a href="mailto:'.$kiri[epost].'">'.$kiri[nimi].'</a>';
} else {
$nimi = $kiri[nimi];
}

Sisu muutujale $sisu. Kui sisu oleks vaja mingil põhjusel töödelda, siis siin oleks õige koht seda teha. Näiteks emotikoni piltide lisamine vms.

$sisu = $kiri[sisu];

Kui $tsitaat on määratud ja rea number vastab tsitaadi numbrile, tõstan selle formi jaoks kõrvale

if ( isset( $tsitaat) and ( $tsitaat == $my_counter )) {
$f_sisu = $kiri[nimi].":n------n".$sisu."n------n";
}

IP aadressile nimekuju andmine. Kui ei leita jääb lihtsalt IP aadress

$ip = gethostbyaddr( $kiri[ip] );

Siin väljastan saadud kirje. Formaadi valik on maitseasi, mina valisin iga kirje jaoks oma tabeli. Ühtlasi panen alla tsiteerimist võimaldava lingi.

<table cellspacing="0" cellpadding="5" width="100%" border="0" align="center" bgcolor="#000000">
<tr bgcolor="#000066"><td align="left"><?=$my_counter?>. <?=$nimi?></td>
<td align="right"><font size="-1"><?=$kuupaev?></font></td></tr>
<tr><td align="left" colspan="2"><?=$sisu?></td></tr>
<tr bgcolor="#000033">
<td align="left"><font color="#000099" size="-1"><?=$ip?></font></td>
<td align="right"><font size="-1">
[<a href="<?=$PHP_SELF?>?alates=<?=$alates?>&tsitaat=<?=$my_counter?>#kala">tsiteeri</a>]
</font></td></tr>
</table>

Liidan väljatrüki loendurile ühe juurde

$my_ocounter += 1;

Sulgen faili

fclose ($fp);

Sellesse punkti jõudes tean ma, palju on ridu failis. Siin võrdlen, kas neid on rohkem, kui väljatrüki aknasse mahub

if ( $my_counter > $maxridu ){

Kui selgub, et on, hakkan genereerima lehekülgede jaoks linke

for( $i = 0; $i< ceil(( $my_counter- 1)/ $maxridu); $i++ ) {
?>
<a href="<?=$PHP_SELF?>?alates=<?=$i?>"><?=($i*$maxridu+1)?>-<?=($i*$maxridu+$maxridu)?></a>&nbsp;
<?php
} // for
?>

Lisamise formil kontrollin veateate olemasolu ja vajadusel trükin teated välja .
Veateade ja ka formi elemendid vea korral tulevad sisse läbi sessiooni muutujate. Peale nende kasutamist vabastan sessiooni nendest muutujatest.

<?php
if ( isset( $message )) {
foreach( $message as $key => $value ) {
?>
<tr bgcolor="#000033"><td align="center" colspan="2"><b><font color="#FF0000"><?=$value?></font></b></td></tr>
<?php
} // foreach
foreach( $formi_sisu as $key => $value ) {
session_unregister( $value['vali'] );
}
session_unregister( 'message' );
} // if
?>

Formi moodustamine, kui element on määratud, panen selle formi

<tr><td>Nimi :</td>
<td><input type="text" name="f_nimi" value="<?=(isset($f_nimi)?$f_nimi:'')?>" size="50"></td></tr>
<tr><td>e-post :</td>
<td><input type="text" name="f_epost" value="<?=(isset($f_epost)?$f_epost:'')?>" size="50"></td></tr>
<tr><td valign="top">Kiri :</td>
<td><textarea type="text" name="f_sisu" cols="40" rows="5"><?=(isset($f_sisu)?$f_sisu:'')?></textarea></td></tr>


Et teada kaua skript lehte genereeris, võtan skripti alguses aja

$mtime = microtime();
$mtime = explode(' ',$mtime);
$mtime = $mtime[1] + $mtime[0];
$start = $mtime;

Skripti lõppemisel võtan uue aja ja kirjutan vahe välja

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$lopp = $mtime;
$total = round( $lopp- $start, 6);
echo “Lehe laadimine v&otilde;ttis $total sekundit”;

#


Külalisteraamatu administreerimine – admin.php

See moodul on sisuliselt täiustatud variant külalisteraamatust, seega peatun ainult olulisematel erinevustel.
Administreerimise moodul saab aru järgmistest GET parameetritest:
alates= lehekülg – mitmendat lehekülge näidatakse.
muuda=suva – muutmise loogika aktiveerimine
f_id=kirjenumber – millist kirjet muudetakse

Kontrollin, kas muutmise kask on olemas ja kas kirje on määratud. Kui on annan formi kaudu kirje numbri edasi ja määran formi action-iks muuda.php

<?php
if ( isset( $muuda ) and ( $muuda == 1 ) and isset( $f_id )) {
?>
<form method="post" action="muuda.php">
<input type="hidden" name="f_id" value="<?=$f_id?>">
<?php } else { ?>
<form method="post" action="lisa.php">
<?php } ?>

Siin vaatan, kui muutmisele mineva kirje id on sama käsitlemisel oleva id-ga teen valmis formi elemendid

if ( isset( $f_id ) and ( $f_id == $my_counter )) {
foreach( $formi_admin as $key => $value ) {
$vali = $value['vali'];
$$vali = $kiri[$key];
}
}

Kui formi element f_ip on määratud, saadan selle ka formiga edasi

<?php
if ( isset( $muuda ) and ( $muuda == 1 ) and isset( $f_ip )) {
?>
<input type="hidden" name="f_ip" value="<?=$f_ip?>">
<?php } ?>

#
Tekstipõhise külalisteraamatu kood

Artikli kommentaarid

O