ugrás a tartalomhoz

mysql_fetch_array és foreach kérdés

thomk · 2009. Szep. 26. (Szo), 18.32
Íme a probléma:
(csak példa)

<?php
include "db/database.php"  //csatizik a mysql adatbázishoz.
$query = "SELECT * FROM users";
$eredmeny = mysql_query($query);
$field = mysql_fetch_array($eredmeny, MYSQL_NUM);
while ($field = mysql_fetch_array($eredmeny, MYSQL_NUM))
{
print stripslashes($field[1]); //egyik próbálkozás, kimenet: a felhasználó jelszava, de csak az egyiké, és ez a baj
echo "<br><br>";
foreach($field as $curr)//itt megpróbálom bejárni, de akkor csak zagyvaságot ír ki a kimenetben. stripslashes-el vagy nélkül ugyanaz.
{
print stripslashes($curr[1])."<br>"; 
}
}?>
Az adat tábla így néz ki:
user jelszo
pistike anyu
(ezenkívül több mező is van, de azt fölöslegesnek tartottam ide leírni.
mezők pl.: id, sid, email, lastonline stb...)

Tehát a probléma az hogy csak az egyik felhasználót írja ki, vagy rakja bele a tömbbe és nem az összeset a 12-ből.

Már próbáltam fetch_assoc -al is és fetch_object -el is, de nem akarja kiírni az összes felhasználót.
Azért azt leszögezném, hogy én még kezdő vok a php-ban. :D

Ez azért lenne fontos számomra, mert erre építeném majd a ellenőrzést, és a jelszó dekódolását is.
 
1

Fetch

gphilip · 2009. Szep. 27. (V), 11.53
A MySQL fetch függvények csak egyetlen rekordot térítenek vissza az lekérdezés eredményéből, aztán léptetik a lekérdezés belső mutatóját.

Ha a while ciklus feltételeként adod meg a fetch függvény értékátadását, akkor így végigmehetsz az egész result seten, hiszen az értékadás mindig igazzal tér vissza, amíg a lekérdezés mutatója a végére nem ér, mert ekkor hamis értéket ad vissza a fetch, és az értékadás is hamis lesz.

Ezért ha minden rekordra kíváncsi vagy, akkor valahogy így kell, hogy kinézzen a kód:

<?php  
	include "db/database.php"  //csatizik a mysql adatbázishoz.  

	$query = "SELECT jelszo FROM users";  
	$eredmeny = mysql_query($query);  

	while ($field = mysql_fetch_row($eredmeny))  {
		echo stripslashes($field[0]), "<br/>"; 
	}
?> 
Mik változtak?

1. tagolás - nagyon fontos, mindig kötelező
2. a SELECT-ben érdemes csak annyi oszlopot kiválasztani, amennyivel foglalkozol. Így a mezők sorrenjét is megszabhatod, és nem leszel bajban, ha esetleg be kell szúrnod egy mezőt a táblába, és borul a sorrend mindenhol
3. A mysql_fetch_array($eredmeny, MYSQL_NUM) egyenértékű a mysql_fetch_row-val, ez utóbbi azonban egyszerűbb
4. kiírásnál légy következetes, vagy echo, vagy print, de inkább echo, mert ennek nincs visszatérési értéke, tehát gyorsabb
5. <br> helyett használj <br/>-t, hiszen ez a valid XHTML soremelés

Kiíratás helyett használhatsz tömbbe helyezést is, ugyanígy.

BTW mire kell a stripslashes neked? Nem htmlspecialchars vagy ilyesmire gondolsz?

Remélem segítettem, kérdezz bátran!
2

Válasz

thomk · 2009. Szep. 27. (V), 16.52
Hát a kódot a tankönyből másoltam, és aztán módosítottam a saját igényeimhez, és onnan jött a dolog. XD

Amúgy még olyat is láttam, hogy valaki a query -ben az általad leírt helyett ilyet írt:
"SELECT * FROM users WHERE user='".$felhasznalo."'"
és csak azokat a mezőket kapja vissza.

Az egész pedig nekem úgy kellene, hogy a felhasználó beírja felh. nevét és jelszavát és ezeket egyezteti a progi a mysql-ben lévőkkel, és ha egyezik akkor tovább engedi, és berakja őt SESSION -ba, és add neki egy session_id-t.
Ennek nagy része megvan(session), csak az ellenőrzés gagyi, a felhasználó név ellenőrzése jó, de a jelszóé nem.
A jelszó kódolva van a mysql-ben, és azt decryptálom és aztán egyeztetem, hogy egyezik e a felhasználó által beírttal.

Tehát akkor, hogy lehet megoldani azt, hogy a felhasználó nevének sor számával(mysql-ben) megegyező sor számú jelszó-t vizsgálja a progi?

EDIT:
Kipróbáltam amit írtál, de abban az esetben is csak az első rekord-ot tudom elérni.
ha echo $field[1]; -et írok akkor a kimenetben már nincs semmi. Pedig a második felhasználó jelszavát kéne kiírnia.

EDIT2:
Az úgy nem lenne jó, ha a lekérdezésbe ezt írnám:
"SELECT jelszo FROM users WHERE user=' ".$felhasznalo." ' " ?
És akkor csak a jelszót kellene vizsgálni. :)
3

Mélyebben

gphilip · 2009. Szep. 27. (V), 16.55
Hali!

Először leírok egy pszeudo-kódot, hogy hogy nézhetne ki az azonosítás, aztán leírom, hogy mire figyelj oda. Nagyon fontos, hogy mielőtt komoly fejlesztésekbe kezdesz, megértsd azokat a biztonsági sebezhetőségeket, melyek fenyegetnek téged és a programod felhasználóit.

A kód nem tartalmaz semmiféle komoly keretrendszerekre jellemző osztályt vagy design patternt, egy egyszerű procedurális kód lesz, ami működhet nálad.

<?php    
  // elindítod a sessiont
  session_start();
  include "db/database.php"  //csatizik a mysql adatbázishoz.    

  $query = "SELECT user FROM users WHERE user='%s' AND jelszo='%s'";    
  $eredmeny = mysql_query(
    sprintf($query, 
      mysql_real_escape_string($_POST['username']),
      mysql_real_escape_string($_POST['password'])
    )
  );
  
  if ($field = mysql_fetch_row($eredmeny) && 1==mysql_num_rows($erdmeny))  {  
  	// az azonosítás sikerült
  	echo "Köszöntünk, ", htmlspecialchars($field[0]), "!";
  	$_SESSION['user']=$field[0];
  	session_regenerate_id();
  } else {
  	// az azonosítás nem sikerült
  	echo "Hibás jelszó, próbálj újra!";
  } 
?>
A lényeg:
1. elindítod a sessiont. Ez minden olyan oldalon kell majd, ahol a session változókhoz hozzá akarsz férni.

2. előkészíted a lekérdezést, mely azokat a felhasználókat adja vissza (ideális esetben 1-et), amelyeknek a megadott érték a felhasználóneve és jelszava. Az adatbázisban legyen UNIQUE és NOT NULL a felhasználónév mező

3. a lekérdezésbe elhelyzed azokat a változókat, melyekre szűrni szeretnél. Ezt pl egy POST html formból kaphatod meg. nagyon fontos, hogy escape-eld ezeket a váltózokat, különben könnyen mysql injection áldozatává válsz.

4. Ha a lekérdezés egy és csakis egy eredményt hoz vissza, akkor sikerült az azonsoítás, a session változóba beírhatod pl a felhasználónevet. Mikor az user által kapott inputot kiíratsz neki a képernyőre, midnig escape-eld valamivel (pl htmlspeciachars), különben könnyedén xss támadásba futsz. Szinten fontos a session ID újragenerálása, hiszen egy session fixation támadást így ki tudsz védeni.

5. ha nem sikerült az azonosítás, akkor kiírjuk, hogy sorry.

A kódból hiányzik még pár dolog, pl ellenőrizhetnéd, hogy a felhasználónév és jelszó nem hosszabb-e az előírtnál (es esetleges biztonsági kockázatot rejtene), illetve hogy az engedélyezett kataktereket használja-e. Szinten nagyon fontos, hogy védd a login részt a brute force támadások ellen, így pl mentsd el, hogy mikor próbálkozott legutóbb a felhasználó sikertelenül a jelszóval, és ha 10mp-en belül újra próbálkozik (lehet akár 5 is), akkor ne engedd belépni!

Ha a jelszó hash-elt (annak kell lennie mindig és SÓZNI KELL!!), akkor a lekérdezés paraméterében a hash-elt stringet kell átadnod ugyanazoknak a szabályoknak megfelelően, amiben bekerült.

Nem futtattam le, de menie kell... lehet, h vmit elírtam. Ha maradt kérdésed tedd fel bátran!
4

köszi.

thomk · 2009. Szep. 27. (V), 17.43
Köszönöm szépen!
Még egy valami...
A jelszó hash-elést kifejtenéd nekem bővebben légyszives?

Nekem most így néz ki:
Kódolás:

function encrypt($text){
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, SALT, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); 
}
dekódolás:
function decrypt($text)
    {
        return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, SALT, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
    } 
És ezt használom a kódban.
5

Cikk

gphilip · 2009. Szep. 27. (V), 17.56
itt egy elég friss kérdés a weblaborról, ebben a témában:
http://weblabor.hu/forumok/temak/102464

A hozzászólások között van pár értékesebb darab.

A te általad használttal annyi a baj, hogy nem hash, hanem egy sima titkosító algoritmus.

A hash-elésnek az a lényege, hogy nem fejthető vissza ideális esetben. Minden lehetséges esetet leképzünk egy hash térre, melyben egyenlő eloszlásal feletetünk meg pl jelszó szövegeket pl 32 bites számoknak (md5). Ez azonban nem fejhető vissza a hash algoritmus természetéből adódóan, maximum szivárványtáblákkal kereshető.

Szerintem alapvetően jó hash-elés:

$passhash=sha1($salt.$password.$user);
Ebből csinálj egy függvényt vagy esetleg egy osztályt.

A salt egy általad kitalált, site-ra egyedi karakterlánc. Ez biztosítja, hogy a password hash ne legyen összevethető más rendszerekből ellopott, ugyanígy hash-elt jelszavakkal. Az usernév azért kell, hogy az egyes userek jelszavainak egyezőségét ne lehessen könnyen vizsgálni.

Amikor egy új jelszót szúrsz be az adatbázisba, akkor ugyanezzel a módszerrel kell hash-elned, illetve mikor a belépésnél a jelszót vizsgálod, akkor a felhasználó inputját szintén ezzel kell előbb átalakítanod.
6

Még mindig nem jó...

thomk · 2009. Szep. 28. (H), 20.04
Még mindig valami rossz...
Azt vettem észre megint, hogy csak egy rekordot tárol a tömböm.
megpróbálom mysql_fetch_assoc -al.
7

Egy sor

gphilip · 2009. Szep. 28. (H), 22.13
Hali!

Mint írtam fent, a fetch függvények egyszerre csak egy rekordot hoznak vissza. Sajnos a PHP alap mysql API-ja nem támogatja az összes rekord lekérését egy függvénnyel, de erre könnyen megírhatod a saját függvényed. Csak ez a while kell bele és egy push a tömbbe ([]).

Asszem pl Postgre-ban van ilyesmi.

De mire kell neked ez, miért nem jó a while?
8

Megoldva!

thomk · 2009. Szep. 29. (K), 17.08
Megoldottam!

if( $felhasznalo != '' )
{  //ha van felhasznlnk
$_SESSION['bejelentkezve'] = 0; //akkor a sütink érétke 0
$jelszo = $_POST['pwd']; //jelszó meghatározása

		$bekodoltjelszo = bekodol($jelszo, $felhasznalo);
		
		$parancs = "SELECT jelszo FROM users WHERE user='%s'";
		$eredmeny = mysql_query(sprintf($parancs, mysql_real_escape_string($felhasznalo)));
		$field = mysql_fetch_assoc($eredmeny);

		
		foreach($field as $users)
		{
			$users = explode(' ',$users);
			
				if($bekodoltjelszo == $users[0])
				{
				$_SESSION['felhasznalo'] = $felhasznalo;
				$user_id = session_id();
				$cmd = "UPDATE users SET sid = '".$user_id."' WHERE user = '".$felhasznalo."'";
				mysql_query($cmd);
				$_SESSION['bejelentkezve'] = 1;
				$cmd6 = "UPDATE users SET bejelentkezve = '1' WHERE user = '".$felhasznalo."'";
				mysql_query(cmd6);
				
				break;
				}
				else
				{
				echo "Rossz Felhasználó vagy jelszó!";
				break;
				}
		}
}
Így már prímán müxik, a továbbiakban még megírtam hogy mi jöjjön ki ha a felhasználónk bejelentkezett, és így már csak design maradt. :)
9

It is a tribute to you to

learn66 · 2010. Aug. 25. (Sze), 12.10
It is a tribute to you to take the cover off this thing. I think this sent a message of what People First, Performance pass4sure E22-280 Now means. Action is better than words. And I think it will sent message that you mean business. This will be good for you and for MCA. As a member of the public, I am interested to find out who planned pass4sure HP0-S24 the scam and who were involved. There will not be any closure until these people are punished and punished severely. This must be done quickly else the anger will mount. As it is we see one law for the rich and powerful and another law for pass4sure HP0-S25 the ordinary people. I hope you can emphasize to MACC not to drag its feet. Otherwise the stigma of cows and cars will bear home. The government have a lot of thing to do correctly to gain back credibility and trust. I hope you will not let this be pass4sure 000-201 one of the thing that got lost along the way. It should not be an item in the next election. The faster this get disposed the better it will be. a small congratulation