invalid argument foreach()
Ik krijg dan deze foutmelding te zien:
De error zit op lijn 28
Het bestand login.php ziet er als volgt uit:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
require 'login-libs.php';
require 'connect.php';
login_check_is_email_provided();
// check that the password is provided
if(!isset($_REQUEST['password']) || $_REQUEST['password']==''){
login_redirect($url,'nopassword');
}
// check that the email/password combination matches a row in the user table
$password=md5($_REQUEST['email'].'|'.$_REQUEST['password']);
$r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'"'
;
$result=mysql_query($r);
if($result==true){
login_redirect($url,'loginfailed');
}
// success! set the session variable, then redirect
$_SESSION['userdata']=$result;
$groups=json_decode($result['groups']);
$_SESSION['userdata']['groups']=array();
foreach($groups as $g)$_SESSION['userdata']['groups'][$g]=true;
if($result['extras']=='')$result['extras']='[]';
$_SESSION['userdata']['extras']=json_decode($result['extras']);
login_redirect($url);
?>
require 'login-libs.php';
require 'connect.php';
login_check_is_email_provided();
// check that the password is provided
if(!isset($_REQUEST['password']) || $_REQUEST['password']==''){
login_redirect($url,'nopassword');
}
// check that the email/password combination matches a row in the user table
$password=md5($_REQUEST['email'].'|'.$_REQUEST['password']);
$r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'"'
;
$result=mysql_query($r);
if($result==true){
login_redirect($url,'loginfailed');
}
// success! set the session variable, then redirect
$_SESSION['userdata']=$result;
$groups=json_decode($result['groups']);
$_SESSION['userdata']['groups']=array();
foreach($groups as $g)$_SESSION['userdata']['groups'][$g]=true;
if($result['extras']=='')$result['extras']='[]';
$_SESSION['userdata']['extras']=json_decode($result['extras']);
login_redirect($url);
?>
heeft iemand een idee hoe ik dit moet verhelpen?
bvd Jules
Gewijzigd op 25/12/2012 23:46:13 door Jules Kreutzer
1) De error vertalen
>> Invalid argument supplied for foreach
Vrij vertaalt: "Er is een verkeerd argument gegeven aan de foreach"
We weten dus dat het een verkeerd argument betreft, we moeten dus kijk wat er straks tussen () staat.
2) De regel opzoeken
Oké, we weten nu de error opzoek naar de regel:
Oef, eerst even normalizeren:
Oké, iets in ($groups as $g) is verkeerd. Het moet dus $groups zijn die verkeerd is.
3) Informatie verzamelen
Laten even informatie gaan verzamelen, hoe wordt $groups bijvoorbeeld aangemaakt?
Hmm, dat geeft niet veel informatie.
4) Je verwachtingen controleren
Je verwacht dat $groups een array is, anders stop je hem niet in je array. Laten we die gedachten eens controleren door de assert functie te gebruiken, hiermee kun je aangeven dat je iets verwacht zoniet dan krijg je een USER_WARNING op je scherm:
Ik verwacht dat je hier een warning voor gaat krijgen, de $groups bevat dus geen array, hmm....
5) De documentatie doorlezen
Laten we dan eens gaan kijken in de documentatie over die functie: json_decode
Het eerste wat mij al opvalt is de 'mixed' in het functie-voorbeeld in het 'description' blok. Hij hoeft dus niet per se een array terug te geven.
Vervolgens kijken we in het 'Return values' blok, aangezien dat het geen is dat we willen weten:
Quote:
Returns the value encoded in json in appropriate PHP type. (...) NULL is returned if the json cannot be decoded or if the encoded data is deeper than the recursion limit.
Hmm, hij kan dus ook NULL returnen. Laten we dan eens gaan kijken of hij NULL terug heeft gegeven:
Hoogstwaarschijnlijk krijg je hier geen error over, de waarde is dus NULL. Dan kun je dit debug proces weer herhalen om erachter te komen wat er fout is (is het een ongeldige jSON string? Is het recursie limit te hoog?)
Misschien is er ook een andere oplossing die makkelijker is, dan wil ik die ook best wel gebruiken hoor.
Jules
Ik zou niet weten wat er fout is, ga nog eens alle stappen af en probeer zo het probleem te achterhalen.
Verder lijkt het erop dat je een json string uit je database gaat krijgen hier. Dat riekt ook naar een erg slecht ontworpen database.
Volgens mij kan je beter het advies dat Ger in een ander topic al gaf ter harte nemen....
Gewijzigd op 26/12/2012 01:15:16 door Erwin H
Code (php)
1
2
3
4
5
2
3
4
5
<?php $r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'"'
;
?>
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'"'
;
?>
naar:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'" and groups = ["_superadministrators"] OR ["_administrators"]'
;
?>
$r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'" and groups = ["_superadministrators"] OR ["_administrators"]'
;
?>
Wanneer ik nu op login klik, krijg ik echter wel nog de link redirect te zien. wanneer ik daar op klik, zou ik normaal op index.php moeten uitkomen, maar hij laat toch nog steeds het loginscherm zien. Dus de sessies zijn niet gezet...
bij login.php wordt verwezen naar login-libs.php (waar ook de redirect link wordt gemaakt). Dit bestand ziet er zo uit:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
require 'basics.php';
$url='/';
$err=0;
function login_redirect($url,$msg='success'){
if($msg)$url.='?login_msg='.$msg;
header('Location: '.$url);
echo '<a href="'.htmlspecialchars($url).'">redirect</a>';
exit;
}
// set up the redirect
if(isset($_REQUEST['redirect'])){
$url=preg_replace('/[\?\&].*/','',$_REQUEST['redirect']);
if($url=='')$url='/';
}
// check that the email address is provided and valid
function login_check_is_email_provided(){
if(
!isset($_REQUEST['email']) || $_REQUEST['email']==''
|| !filter_var($_REQUEST['email'], FILTER_VALIDATE_EMAIL)
){
login_redirect($GLOBALS['url'],'noemail');
}
}
?>
require 'basics.php';
$url='/';
$err=0;
function login_redirect($url,$msg='success'){
if($msg)$url.='?login_msg='.$msg;
header('Location: '.$url);
echo '<a href="'.htmlspecialchars($url).'">redirect</a>';
exit;
}
// set up the redirect
if(isset($_REQUEST['redirect'])){
$url=preg_replace('/[\?\&].*/','',$_REQUEST['redirect']);
if($url=='')$url='/';
}
// check that the email address is provided and valid
function login_check_is_email_provided(){
if(
!isset($_REQUEST['email']) || $_REQUEST['email']==''
|| !filter_var($_REQUEST['email'], FILTER_VALIDATE_EMAIL)
){
login_redirect($GLOBALS['url'],'noemail');
}
}
?>
Gewijzigd op 26/12/2012 01:17:28 door Jules Kreutzer
Jules Kreutzer op 26/12/2012 01:14:33:
Ik heb de warning kunnen wegwerken (inclusief een paar andere) door middel van volgende code aan te passen:
naar:
Code (php)
1
2
3
4
5
2
3
4
5
<?php $r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'"'
;
?>
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'"'
;
?>
naar:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'" and groups = ["_superadministrators"] OR ["_administrators"]'
;
?>
$r= 'select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'" and groups = ["_superadministrators"] OR ["_administrators"]'
;
?>
Als je exit() helemaal aan het begin van je script zet ben je ook van alle warnings af....
Dit lost geen enkel probleem op. Wat je nu hebt is een fout SQL statement, waardoor je query gewoon mislukt en je script dus zal afbreken. Ja, je bent dan die php warning kwijt, maar inloggen zal je nooit meer lukken.
Waar het om gaat, in het oorspronkelijke probleem, is dat er in de database blijkbaar een verkeerde waarde staat in de kolom groups en dat dien je gewoon te controleren voor je verder gaat. Dus voor je die foreach in gaat moet je controleren of $groups wel een array is (en dat doe je met de functie is_array). Is het geen array dan kan je gewoon die foreach niet uitvoeren.
Bij de voorbeeldgebruiker, staat er bij groups: ["_superadministrators"]. dit heb ik veranderd bij mijn account naar _superadministrators. Dit heeft echter geen effect.
De index.php pagina vraagt naar de sessie waar de groups gelijk is aan superadministrators of administrators, is dat niet het geval, wordt het login formulier getoont.
Het bestand wat controleert of de group goed is, heet admin_libs.php en ziet er als volgt uit:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
require $_SERVER['DOCUMENT_ROOT'].'/incs/basics.php';
function is_admin(){
if(!isset($_SESSION['userdata']))return false;
if(
isset($_SESSION['userdata']['groups']['_administrators']) ||
isset($_SESSION['userdata']['groups']['_superadministrators'])
)return true;
if(!isset($_REQUEST['login_msg']))$_REQUEST['login_msg']='permissiondenied';
return false;
}
if(!is_admin()){
require SCRIPTBASE.'admin/login/login.php';
exit;
}
?>
require $_SERVER['DOCUMENT_ROOT'].'/incs/basics.php';
function is_admin(){
if(!isset($_SESSION['userdata']))return false;
if(
isset($_SESSION['userdata']['groups']['_administrators']) ||
isset($_SESSION['userdata']['groups']['_superadministrators'])
)return true;
if(!isset($_REQUEST['login_msg']))$_REQUEST['login_msg']='permissiondenied';
return false;
}
if(!is_admin()){
require SCRIPTBASE.'admin/login/login.php';
exit;
}
?>
Ik heb nog niet geprobeert om de groups in de database te verandere naar ['_superadministrators'], omdat ik denk dat het geen verschil maakt...
Jules
Gewijzigd op 26/12/2012 12:01:46 door Jules Kreutzer
Tevens raad ik je aan je database te normalizeren. Zodra je een array-achtige waarde in een cell hebt staan weet je dat het verkeerd is. Hoe ik het zou doen:
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
+-------------------+ +-----------------+ +-------------------+
| users | | roles | | user_roles |
+----+--------+-----+ +----+------------+ +---------+---------+
| id | name | ... | | id | name | | user_id | role_id |
+----+--------+-----+ +----+------------+ +---------+---------+
| 1 | Wouter | ... | | 1 | admin | | 1 | 2 |
| 2 | Jan | ... | | 2 | superadmin | | 2 | 3 |
| 3 | Piet | ... | | 3 | user | | 3 | 1 |
| .. | ... | ... | | 4 | ... | | ... | ... |
+----+--------+-----+ +----+------------+ +---------+---------+
| users | | roles | | user_roles |
+----+--------+-----+ +----+------------+ +---------+---------+
| id | name | ... | | id | name | | user_id | role_id |
+----+--------+-----+ +----+------------+ +---------+---------+
| 1 | Wouter | ... | | 1 | admin | | 1 | 2 |
| 2 | Jan | ... | | 2 | superadmin | | 2 | 3 |
| 3 | Piet | ... | | 3 | user | | 3 | 1 |
| .. | ... | ... | | 4 | ... | | ... | ... |
+----+--------+-----+ +----+------------+ +---------+---------+
Jules Kreutzer op 26/12/2012 12:01:06:
Bij de voorbeeldgebruiker, staat er bij groups: ["_superadministrators"]. dit heb ik veranderd bij mijn account naar _superadministrators. Dit heeft echter geen effect.
Ook dat lijkt me niet verstandig. Wat je dan aan het doen bent is een klein onderdeel van een groter geheel veranderen. Het grotere geheel zou echter als geheel moeten werken. Als dat het niet doet moet je niet lukraak iets veranderen, maar eerst begrijpen hoe het werkt.
Uit alles wat je verteld heb begrijp ik dat er een json encoded array in een database veld staat (in groups). Als je daar nu een normale waarde van maakt, dan zal je json_decode misgaan en daarmee ook je foreach loop, want je krijgt er namelijk geen array meer uit. Waar de fout dan wel ligt, geen idee.
Wat ik wel kan zeggen is dat ik dit script al veel eerder in de prullenbak zou hebben gegooit. Het staat bol van de fouten of in elk geval verkeerde dingen. Vooral het gebruik van json encoded gegevens in een database, waar je (zoals Wouter helemaal terecht opmerkt) een genormalizeerde structuur zou moeten toepassen is echt een grote no-no.
Toevoeging op 26/12/2012 14:02:45:
Het is opgelost,
Wanneer ik het op mijn locale host teste kreeg ik de http-500 error, ik heb dat opgelost (geprobeerd in ieder geval) door $r om te zetten naar $result.
Maar wanneer ik op mijn webserver het orginele bestand upload, werkt het wel, en is het ook mogelijk om ingelogd te worden.
orginele login.php:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
require 'login-libs.php';
login_check_is_email_provided();
// check that the password is provided
if(!isset($_REQUEST['password']) || $_REQUEST['password']==''){
login_redirect($url,'nopassword');
}
// check that the email/password combination matches a row in the user table
$password=md5($_REQUEST['email'].'|'.$_REQUEST['password']);
$r=dbRow('select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'" and active'
);
if($r==false){
login_redirect($url,'loginfailed');
}
// success! set the session variable, then redirect
$_SESSION['userdata']=$r;
$groups=json_decode($r['groups']);
$_SESSION['userdata']['groups']=array();
foreach($groups as $g)$_SESSION['userdata']['groups'][$g]=true;
if($r['extras']=='')$r['extras']='[]';
$_SESSION['userdata']['extras']=json_decode($r['extras']);
login_redirect($url);
?>
require 'login-libs.php';
login_check_is_email_provided();
// check that the password is provided
if(!isset($_REQUEST['password']) || $_REQUEST['password']==''){
login_redirect($url,'nopassword');
}
// check that the email/password combination matches a row in the user table
$password=md5($_REQUEST['email'].'|'.$_REQUEST['password']);
$r=dbRow('select * from user_accounts where
email="'.addslashes($_REQUEST['email']).'" and
password="'.$password.'" and active'
);
if($r==false){
login_redirect($url,'loginfailed');
}
// success! set the session variable, then redirect
$_SESSION['userdata']=$r;
$groups=json_decode($r['groups']);
$_SESSION['userdata']['groups']=array();
foreach($groups as $g)$_SESSION['userdata']['groups'][$g]=true;
if($r['extras']=='')$r['extras']='[]';
$_SESSION['userdata']['extras']=json_decode($r['extras']);
login_redirect($url);
?>
Toch bedankt voor jullie hulp!!