Sanitize user input to avoid XSS attacks Question
I have username and password for login and want to avoid the cross site scripting. I read that using
htmlspecialchars()
is the way to go but not sure what to do after that. Any ideas?937 Replies
current code so far
use prepared statements
how's that work?
https://www.php.net/manual/en/pdo.prepare.php
you feed the raw string to PDO and PDO makes sure it's safe for the database no matter what
also, you don't need to sanitize the password because you're hashing it anyway
(you are hashing it, right?)
im using the
password_hash()
function but i know there's an argon option which I dont know how to use
is what im doing not a good thing?yeah, you can use password_hash. Just hash the raw value from the user, and store the hash in the database
hashing will guarantee a database safe string, but still use prepared statements to insert things. You should always use prepared statements rather than trying to sanitize your own data
my goal was sanitize input for errors and report it so user can't proceed if they try to do anything stupid with xss
best security practice is to not notify people doing stupid things with xss
basically, you just silently sanitize and use the sanitized input
hmm
so me making a sanitize.php file is kinda a waste?
yeah, honestly
anything you do for security, you want to try to hide from the user as much as possible
you technically don't even want to tell them if the username or password is the one that's wrong, that lets people try to find usernames by just flooding your login and seeing if it returns "user unknown" or "password incorrect"
trust that PHP's standards are good enough to protect you, use prepared statements and password_hash
see I made this form checker file to use functions from in register and login
now im just trying to make sure xss crap is avoided
see, that's fine. None of that will leak info (though upper character limits for passwords are pointless)
Just don't manually try to sanitize your user's inputs, trust PHP. That way, when there's a vulnerability, you just update PHP and that's that
ok so
if I use prepare, how to handle htmlspecialchars?
on display
or, alternatively, when you store them in addition to the prepared statements, but only for things you might conceivably display. Never for the password
htmlspecialchars won't take care of even the most basic SQL Injection attacks
what does?
prepared statements
they're made to prevent SQL injection
htmlspecialchars will help mitigate XSS
but yeah, never mess with the user's password, it's just going to cause issues and you shouldn't ever store or display the user's password anyway, not unhashed
what if they put xss attack in password field?
how would that ever trigger?
xss is a worry if the value is displayed to a different user
once an attacker has submitted their XSS attack in the password field, your code should hash it as is and that destroys the payload.
you're doing some things in a very very wrong way
1- you're sanitizing emails - just validate and gtfo
if it doesn't pass as an email, it isn't an email and no sanitization will save it
if it is an email, you should accept the input
you can sanitize the email after, but it should be safe
(I'd argue you should still sanitize before display though
2- you're limiting the maximum length of your password
DO NOT DO THAT
i dumped the email for sign
and changed the maxium password
set it to 256 characters or something, if you really must
30 characters isn't safe enough, sometimes
3- you're not trimming whitespaces
people are dumb and copy stuff, so, trim whitespace
72 bytes is the limit for bcrypt, but there's no reason to limit the password at all
PASSWORD_DEFAULT
doesn't
and the argon2 ones don't as well
just bcryptok i got some stff started
require __DIR__ . '../../../vendor/autoload.php';
<-- this is scaryuse
PASSWORD_DEFAULT
insteaf of specifying a specific algo
instead of doing this, just use the composer psr4 loader you were using before
changed
you have a bug
if(isset($_POST[$htmlName]))
<-- this will give you false positives
use !empty()
instead
wait
oh boy ...
i got what that function does and it's completely uselessim very rusty at php
how i include them?
instead of using that function, use
?? null
or something"MD<insert name here>"
use MD/helpers/formcheck
capitalization is important
you have a loader, so, all you have to do is just use the classes
you don't have to include the files, as they are automatically included for youphp is complaining
Undefined function 'validateRegisterFields'.intelephense(P1010)
then you did something wrong
not
include
use
the psr4 loader does all the work for you
complains
syntax error
what does it say?
probably wrong slashes
syntax error, unexpected token "/", expecting "," or ";"
yeah, told you the wrong slashes
change then for the
use
ah
it complains that I setup wrong
because I dont have class in formcheck.php
then do it
make it all into a class
make it a generic validation class
and make one for sanitization
`
just complains I dont have a defined type
this is getting confusing
that's because you're doing too much
here's what i would do:
1- make a class to validate strings
2- validate strings
3- get the errors, if there's any
now, you do you, but, i would put those 2 functions as 2 static methods in a class
im just struggling
been a while since I had to think this way
ive never done oop php just php before oop
this isn't even the hardest part
but why don't you make a generic class to validate stuff?
because I never thought about it
the idea of classes is to make stuff re-usable
and separate responsibilities
i could make a class have an array of input i guess since there's different fields between both pages
or, make something generic
then you can validate anything
yeah im not sure how to do that in php
and since it is a custom class for you, you can add specific validations
how about a class that you can pass a value, and it validates if the value is something
and if that something is what you expect
that's really not generic at all, but it's a move forward
how would you do it?
i could just split it up into validating things separately
a class that has a function that accepts a value and an array of what you want to validate
and that array could be like
['email', 'required']
or ['string', 'maxlen' => 50, 'minlen' => 10, 'regex' => '@^[a-z]+$@i']
then the function validates if it is a string, the length, and the regex, or the email and if it exists
or just a method for everything, and you use chaining to get you the result
something like Validate::post('key')->email()->required()->valid()
, and it returns either true
or an array with errorsPHP
PHP Tutorial
PHP sanitize() Input Function
In this tutorial, you'll learn to develop a reusable PHP sanitize() function to sanitize inputs.
or just sprinkle that all over
that's valid as well
but don't use sanitize, use filter_var
ok
im just lost
this all I got so far
too many decisions, i know
it's fine, you can leave as it was and just use it
it's not the best, or optimal, but if it works then it works
well if you want to you can share better code
so I can learn
i wouldn't say i could write the best, but different
i have my style, and i don't think my style is the best for you
well if your idea is more optimal I should learn it too so next project I can improve
i mean php isnt the same as it was in 2012
so im having to relearn it
that's alright, i will come up with something
Thanks
Tbh my day is now a mess so any more confusion will get me nowhere
i have a simpler idea for you
write a class to validate the email, the password and the username (if you have one)
should be a lot easier
i was thinking too overcomplicated
a class for each?
or just what i already have?
no, for all
i made separate files for each
validateusername.php and validatepassword.php
something like this
I dropped email
you get the gist
2nd if has an error
...
says "expression expected"yeah, because it's pseudocode
since
FILTER_SANITIZE_STRING
is deprecated
what are my options for a username?none, use
htmlentities
with an encoding
or leave it null to use utf8 (default)for password
what about
ENT
stuff?
ENT_IGNORE? DISALLOWED, ?try it
i just did whatever
i came up with this
here's register.php
im thinking the validate class is brought in and since it has two return types... maybe I need two
updated register.php
does this work?
So tomorrow how should I display these
$errors[]
that's the fun part: any way you want
if you use ajax, send it over ajax
if you only have php, make sure the errors are accessible where you render the form
That's the part I'm not sure about
Since it's an array, I'm not sure how to display the proper messages in my html
GitHub
PHPTodoApp/app/views/register/register.php at main · MD-2016/PHPTod...
practice project to get back into php. Contribute to MD-2016/PHPTodoApp development by creating an account on GitHub.
That's what I got so far
how are you passing the into to the file?
Well the validation happens when the user hits submit
When
isset
is triggered for submit buttondoes javascript send it? or is it a normal post?
Normal Post
I didn't know how to do Js sending it
then, where the form is, just render the messages
how you render, varies based on the contents of the errors variable
you can output it on the top of the form
you can store the errors on an array with the key based on the name, and then for each field you output a message
it's, almost literally, "loop and print"
So an associate array
if you want
you're asking about something that is very "do what you want" because there's no "right" way to do it
just better or worse
Then for each loop in the html above the fields and top of form
something like that, yes
Ok I'll have to try that tomorrow
i can't give you a definitive answer because there isn't one
but what you said is a good way to do it
it isn't the best because there isn't one
you code could use TONS of improvements
Yeah since I haven't used any js it made me wonder if it was more appropriate for form checking and only having php handle the requests
it's fine, both are fine, both work
Yeah my code is sloppy 😦
it's not sloppy
just can be a lot better
What improvements are you suggesting?
re-doing everything from line 6 to 30
^ this doesn't do anything and may actually cause issues because it throws warnings
^ you don't need this: if
$errors
is empty it means a success
^ this is a loop
but you're doing it manuallyI wasn't sure how to handle the
$errors ?: true
situation with this codethe what???
GitHub
PHPTodoApp/app/class/helpers/formcheck.php at main · MD-2016/PHPTod...
practice project to get back into php. Contribute to MD-2016/PHPTodoApp development by creating an account on GitHub.
oh, that
im just saying that you're doing what a loop does, but you're doing it manually
How do I do it in a loop since the return was
?:
what does that have to do with anything?
I'm bringing those functions
From formcheck
what's the problem with
?:
?That's a ternary return meaning it could be a string or boolean?
yes, and?
what's confusing about that?
Never seen it before so I wasn't sure how to handle it with using it in my register page
you handle it is pretending it doesn't exist
it's an implementation detail of the function
just set the correct return types and you're good to go
So the correct return type is a boolean?
no
the correct type is an array OR a boolean
array|bool
8.x lets you define multiple typesOk that's kinda new
it's from 8.0
Yeah I'm reading
you were overthinking
so i deleted the code from line 6
just kept the errors string array and required boolean
does it work?
i havent done anything in
if(isset($_POST['submit'])) {
// check the user input before database connection
// code here for success and start database connection and prepared statement
}
that's 80% of your work done
planning
yeah just thinking about how to do that loop
since I need to check each input, display the proper error message, and call the right functions to validate from the formcheck.php
associative arrays help a lot
maybe an asosciate array with the form element name mapping to the error message?
thing is there is more than one for each
yup
there exist this one amazing thing called "array"
where you can just shove stuff into it, automatically, in numeric order
yeah, you may have 2 errors
that's fine
but my form name can only map to one of them
in an array
you know you can put arrays in arrays?
so a form element name pointing to an array of error messages?
im trying really hard not to tell you what to do, but hinting on a way to do it
yes
that would be thje final result, if there's errors
im just a little confused on putting this all together
I know there's the validation functions I need to call from formcheck.php and they return
array | boolean
, populate the $errors[]
as needed, process the POST stuff
with these 3 variables
what's that
$inputarray
?idk i just made it based on previous discussion
yes the "final result"
why?
sorry just a little lost with this setup
im trying to understand how you are lost
that's the above code I got
what are you trying to do?
can you describe it to me, step by step?
tell me the algorithm
- user hits submit
- validate the username, password, validatepassword fields
- check if their good (true) or display an appropriate error message
- stop on errors from processing above input - only authorize connection to database if input passes
- stop on errors from processing above input - only authorize connection to database if input passes
in a list form, please?
im a stupid robot, and you need to explain to me, step by step, what you want the code to do
define "user input"
username, password, validatepassword
add it to the list
updated
what stops on errors?
processing input
add it to the list
well I got the user hitting submit check with
if(isset($_POST['submit'))
yes, but don't talk about implementation details if you aren't sure of what you're implementing
first, know what you're implementing
define all steps and how it will be processed
then, you write the code
i pretty much defined all the steps
so, if the email is empty, it stops checking that the password is empty too?
the list is wrong then
it says it stops on errors
but it doesnt
it validates all inputs and then decides on what it does
well
either this or I do each one individually
as you should
do you know how to make a flow diagram?
been a long time since ive done programming logic and design
that was like 2009
you should make a flow diagram
i havent done one since 2009 either
that means more studying and I need to get into a job by summer
or it's over for me
i know this sounds like im wasting your time, but you're implementing badly defined features, and you end up with messy undebuggable code that not even a mother would love
maybe im just not meant to be a programmer
open excalidraw and make a flor diagram
my code never been that great anyway
it just worked for school
dude, listen to me
your code isn't "not good" not because of lack of knowledge
you're just waffling about, trying to blindly implement something
but you don't have defined what you will implement
does anyone in this server do that?
do what?
flow diagrams and such
most just write code
and they write amazing code and never ask for help, right?
idk
cdl and I just burned out I guess
you think im not tired?
idk if they write amazing code 😄
ive slept a total of a little above 15 hours these last 3 days
you should rest then 🙂
i've been extremely tired all month
ive been working 9-10 hours almost everyday
what im telling you to do is to stop
stop, organize your head, draw what you are thinking on how it will be implemented, then write the code
right now, you're just doing the equivalent of throwing pasta to a wall and see if it sticks
so, stop, put your ideas into something visual, then do what you need to do
i dont like drawing those diagrams and never did them correctly i mostly just listed this stuff
here's what I came up with thinking back to what I remember
that's everything it should do
but the setup is different so it's a bit harder to see the implementation
step 5 is useless
you don't "check for xss input"
you just output what you need by making it into a safe html string
sorry mom was bugging about adware on youtube talking about "work from home" jobs for companies that dont even hire for those roles
im back now
it's fine
by the way, you forgot the part where you show the errors
"Report error"
is showing the errors
how?
where's the step where the errors will be shown?
will you show the error right after validating?
will you show the errors all together at the top of the form?
will you show the errors by input?
updated
- display the error message to the user
<-- how? where? when?yes, i read the list, but my question is still unanswered
which is an important step
i cant edit it anymore
too big for discord
it's fine, just say it here
- display error message from errors array to the user on top of form
the classic way
implement this for 1 input
been a long time since ive done logic and design
apparently it's killed me not keeping up with it
i can see it, which is why i have to force you to re-think about it
along with data structures and algorithms
but, go ahead and implement this for the email input
i dont use email
took that out
just username for this small project
pick 1 field and validate it
username, validate it
AND ONLY THAT ONE
ok I have the idea but we have an issue
we have this
to start with which is
boolean | array
okay, and the issue is?
so that function is going to check for empty and then add the error to $errors
no, what it is doing is outputting a boolean or an array
otherwise return true
but, again, what is the issue?
you have a boolean, you have an array
I guess check if the boolean is false?
the function outputs
true
or an array
it will never be falseyeah this is confusing
it's not
true = no errors, array = errors
so what am i saying
or
just weird trying to tie this all together
i see where the confusion stems from
you have 2 return types, and you think you need 2 variables for it
but no, you don't
yes the confusion is how this is going into register.php since formcheck.php handles some of the checking
$validateUsername | $errors
<-- this is a bitwise orthe logic makes sense on paper but trying to tie together with the current implemntation details isn't making sense
ok
but im not seeing how to handle it for each input
focus on 1 input
this is why I understood the code I started with
all these "updated changes" made it more confusing
I just know older php
this new stuff is just making it into Java
this has nothing to do with "new" or "old" php
you would have to write the same code in 7.x, 5.6 or even 5.3
the code I started with before we made a lot of changes is what I understood
since you said it was "bad"
ok so I need to do a bitwise or check in the if?
no
since the return type is bitwise or I wont know what im getting
so id have to check for both somehow
it's not bitwise
you are using bitwise operations on the result value, which after testing, i verified that it doesn't work
so do I need to change the result on formcheck.php?
does this need changed then?
you have 2 options:
1- keep as is, and check if it is a boolean or an array
2- change the name of something to indicate that it doesn't have errors, and change the return value to
false
that's the issue was checking if it's a boolean or array
that's where im stuck
return false then
because I have to check it for each
or just return an empty array
and document that it returns an array of errors
let's just start here
so we know the return is
array or boolean
this means we check for either an empty array or boolean?
does php have functions for that?change it to return just the
$errors
variable
it's easier to reason withthere is an
is_array
and is_bool
functions I can use
just try what i said
and lets see how it works
so what I put is wrong?
no
im just telling you to simplify
now it only returns an array
so i would check if the array isnt empty
yup
if it isn't empty, it has errors
i can use
empty()
yes and no
you can, but for THIS VERY UNIQUE AND SPECIFIC EXAMPLE, it is overkill
i guess normal would be
for php
that's checking if the constant
error
isn't set to an empty stringill check if count != 0
or
just use the variable, alone, in the
if
hmm?
if($validateUsername){}
yup
but, you don't have to do it there
just shove it all into an array, with the name of the field as the key
ok i got the
started
so now i need to get the message from the error array and add it to my error array on that page then display it
if you do something like this, you can save A TON of work
ok so I got an errors array already
I just need to populate it with the apprioate stuff
basically, yes, it's an option
like this
no
but it's close
darn
it's really close
very very very close
the variable is useless
$errors['username'] = $validateUsername
go back to the other version
skip assigning that weird long ass variable
idk
all i see is this
PHP
PHP Tutorial
PHP Associative Arrays
In this tutorial, you will learn about PHP associative arrays and how to use them effectively.
dude, do literally what i said
this time, im telling you what to do
ok...
now, what's missing there?
the string from the
$validateUsername
and what supposed string comes from where?
Validate::username()
since you removed the variable, what do you have to do?
very good
by the way, are you using vscode?
yes
so I need to delete that
valdiateUsername
that's the variable? yes, it's utterly useless
ok so what do I put in the if
install the extension first
ive had that installed
before you mentioned it
alright
right now, don't think about it
show me the full code
what's that
if
?that's what's left removing the
$validateUsername
okay
show me the full code
wouldn't that be in the html
the full php file
`
^ what are these for?
same question ^
why are you re-creating the array 3 times, inside of leftover
ifs
?i have no clue
im just following the logic of the steps i wrote out
but now, think about this
you have an array
an array can have multiple keys
correct?
yes
if associative
then why don't you put it all into the same array?
without the if
so do it all in one if?
no
ifs
it's empty for a reason: it's of no use nowvery good
now format is properly
one array value per line
fix the indentation
that doesnt happen on vscode
it's discord
alright
now, you see what you've done?
yeah no ifs
shorted the code
but this means my code in the html will need changed
normally in java i would've used try catch for some error handling
it was wrong in the first place
that's an option, but you can only throw 1 exception per field, while each field may have multiple errors
yeah
next up is
hold there, buster!
you aren't done yet
now, you need to do something when it doesn't have any errors, right?
yeah
i guess santize input and pass to database?
before you even touch that, how do you know if you have any errors?
check if
(!$errors)
but you have 3 values
won't it always be a truthy value?
check if each key has an empty value?
and how do you do that in a concise way?
map?
how about filtering out the empty arrays?
you won't need them, so, toss them out, right?
or you could use
array_key_exists
and is_null
the key will always exist and will never be null since you return an empty array
right
how about you wrap the array into a call to
array_filter
?ok so i need the array and a callback
no, just the array
read the notes
ok default is empty()
yup
so, just
$errors = array_filter([ ... ])
and you're done
since it returns an array
or, just save some lines and put it all together
that's why functions accept values, instead of just variables
but, if you want to be more expressive and explicit, that is perfectly valid
basically, yes
now
$errors
is empty of has something in itno
it's an array
you can't convert an array to strings
so ill need to use a foreach loop
yup
but you know what would be even smarter?
map?
map, but would be better to show the message under the field that generated it
that's the fun part
what "field" shows
what do you mean?
because ill need to see what field is being displayed
brb mom is getting frustrated with the tv
you have the name of the field as a key
this is what i would do
i would check if the
$errors[<field_name>
is empty, then output an <ol>
, loop over the errors - an <li></li>
per error, then outside the loop just output a final </ol>
so more than one error?
they will be ordered numerically
ok so
I need to use a loop
yes
with ifs inside then?
no
no ifs
ok this started
no
that's for all errors, not per field
i see
so I need to check if values of a key are empty
otherwise loop
yup
so that will be 3 ifs or just one?
3 ifs
no, it's an array, not an object
and you can't use empty strings as strings for properties
ok
that should be easy
COUNT_RECURSIVE?
no
hmm
do you want to show all the errors at the top? or on each input?
just inputs that fail
for each input, check if the errors for that name are empty
that works by pure sheer luck
what is the "proper way"
it's not correct, it's not actually working properly
empty
check if it's not empty
so
not empty
yes
that
ok so
this means $errors has one
or more
yes
so i need a loop that says
as $error
don't be so verbose
you know it's an username error`
so close
almost there
i could have it do it inside the form and display each error above the respective field
it's prefered to display under, so it doesn't interfeer with the label
under the textfield?
yup
what's my goof
you check for
$errors['validatepassword']
, then loop for $errors
that's the goofi made it $error
that doesn't fix the goof
also, spans are inline
you will see
error 1error 2error 3
can't have all three named
$error
and the goof is still there
yes you can
so the issue is with validatepassword
no, all of them
that one was an example
oh
very good
but that will output it at the top
ill just add php tags under each field and then check?
yup
very good
that should be enough to show error messages
yep I guess next would be sanitizing input then allowing what's good through to database
however, that's absolutely horribly unsafe
:/
so, ALL error messages have to be made into proper html strings
well after the unsafe is fixed ill have to call it a night
echo '<p>{$error}</p>';
<-- also, this doesn't work
single-quotes are NOT the same as double-quotes
but, in this case, you should keep the single-quotes, and remove the string interpolation
one important thing: echo accepts multiple arguments, like a functionprint better to use?
no
that's a different tool
perfectly valid
but way overkill
ok
sometimes it feels like Go is a bit easier than php
it's newer
or
echo '<p>', $error, '</p>';
this version makes some things a lot easier to handlewhy's that
the arguments are clearly separated
ive mainly seen
.
concat in the docsthis isn't string concatenation
yeah i know
it's just multiple arguments to the echo construct
i never seen commas in echo before
it's kinda new for me
which actually is a tiny tiny tiny tiny tiny tiny micro-optimization
since it doesn't have to concatenate before outputting, it's a bit faster
anything else I need to do before we end?
yes
you need to sanitize the output messages
im not handling anything else outside of error checking at this point it's too late
htmlentities or htmlspecialchars?
i would use both
pick one, stick to it
but i would pick
htmlentities
to avoid issues with quotesok so wrap my $error in it
yes
the default settings should be fine
utf-8?
^ don't touch anything else
just the first argument
yup
that should work
if it doesn't, it will wait for tomorrow
but you understand what's being done?
with that htmlentities
escape any xss code
everything
yes and no, but yes
sort of some of it is interesting but i have to see how to do the database stuff next
spoiler alert: no sanitization will be done
we basically made an array that is filtered with proper error messages then displayed them is the breakdown basic
yup, that's right
and each field is mapped by it's name
I think I can get this down just wll take some time for it click
if I can get that programming logic and design mindset back this will get a lot easier
combined with my data structures and algorithms knowledge
(if I didnt lose it too)
and that means practice
sadly one job im after they dont mention what tech they're using
so it's probably asp.net with C# which means im screwed 😄
c# isnt that hard
as youve seen php is already hard for me
going back to C# would be another long road
60% of the syntax is the same
pushed code to github
nice
The logic makes sense
I just need to get back into a mindset where I break things down better and use a data structure or proper algorithm
that's why i wanted you to make the list
Yeah might do that again tomorrow too
you should rest too
@MD how the progress now?
Some
Already solved then?
I'm currently on writing to the database
Okay, i'm here just to answer this topic question: Sanitize user input to avoid XSS attacks
- Sanitize is more like check the input for required, length, format, etc.
- You don't need convert/encode/escape the input using htmlspecialchars() or htmlentities() when saving the input to database.
- When saving to database, use prepared statements and parameterized queries.
- When displaying the data from database to HTML, then you need to convert/encode/escape the data using htmlspecialchars().
sanitizing is the removal of characters or sequences that aren't allowed for a specific format
however, it is not validation, as sanitizing a string like
a<b>@gmail.com</b>
will/should result in a
, which obviously isn't a valid email addressyes, i mistake it for validate
it's alright
everything else you said is absolutely correct
this is what im onto next
1. Validate the error checking works
2. If good, then work on writing to database
3. After writing to database, start a session, redirect user to their todo page
4. Check for user logging out whether it be through closing browser or logging out
5. ban access to pages without proper login Process for writing to database
6. Check if database is loaded correctly,
- else add an error variable then display as a html element to the screen
1. if database loads successfully, then
- setup a prepare statement with username, and password
- bind the username, and password as parameters to the update query for user table
- execute the update query to the database
which I do know you really shouldn't display a database fail to a user
you can't check if a user closed the browser reliably
also, users close their browsers and expect some sessions to still work
but other than the order being weird, i think you got the right ideas
JS could check for a browser closer
since it's local
yes, but the server shouldn't care about it
but you're right most users want they cookie to continue letting them in for a bit so they dont have to sign
seriously, just don't even bother with the closing
the server deletes the sessions when they are unused
true
so, don't worry about it
I added a try catch for database issue
good, now you can check if hte database failed
for now just displays a message of failure to load database just to have something there for the meantime
that's all you can do, if the database dies
right!
but you have a plan, so, follow it now
way better than no plan, right?
true
right now i got this
so im thinking if database loads then add the post variables to the username and password local variables then do a prepare statement, bind, then execute
how about you have a class that makes it easier for you to do queries and stuff?
and you can check if the database loaded in it, and throw the errors you need from that class
i can add it to my dbhelper
oh, right, you have
SQLConnection
<-- thatyeah right now it just connects
you can add that functionality in the class
got this so far
kinda goofed on that $pdo variable
//error was caught trying to create database connection.
<-- please, avoid comments like these
those do nothing but bloat your code
$encryptedPass = password_hash($password, PASSWORD_BCRYPT);
<-- DO NOT USE BCRYPT!!!
use the default one
by the way, test the cost argument, and check which value is best for your server
aim for 350ms of delay for an answer, to make it unfeasably slow for brute force attacks to be effective within a lifetime
ten for now
since it's local hosted
ill test more after I get more of a working setup
just go for 11
localhosts usually do well with 11
it doesn't like this
$stmt = $pdo->prepare($query);
$pdo being the issue$pdo
doesn't existi have it as a private global variable
yes, but you're using
$pdo
how do you access a private variable in php?oh this isnt java
it is a private global class variable
it can't be private and global
$this
yup
that's it
yes it is java 😄
that's good
however, you have a problem
$query looks odd
it looks odd as hell, but it is fine
the
$options
should be in a class constant
yes, i said "constant"
by the way, use an heredoc with the name SQL
, and vscode enables syntax highlighting into itthis is getting better
no no, the whole array has to be a constant, so you can re-use it
you can make it private as well
by the way, the function is missing a return type and a type on the arguments
im getting there
im not seeing key value const examples
remove that cost constant
put the value into the array
private const OPTIONS = [SQLConnection::OPTION_COST];
no
SQLConnection::OPTION_COST
<-- you don't need this, just put the value directly
oh, btw, you can just use self
instead of typing the class nameno
that's not what i said
read this message carefully
ok i put 11
show me
const OPTIONS = [11];
you're missing the key
the key is mandatory
got it
everything is fixed now
still getting used to the newer php syntax but in time
that's old syntax, supported in php 5.6
yes, but
options
is a very non-specific name
i know this will sound nitpicky, because it is
but you need to create good habits
naming things correctly is very importantive had good habits before
in time
lets focus on task at hand
so is qery and stmt ok?
yeah, it is okay, but you lack backticks around the identifiers
this prevents surprises and syntax errors
huh
i just go by the php page examples
indentation is also very very important
specially if it is tabs: tabs are a must
true
ok
so
"exec" returns an int for the number of affected rows or 0 if none affected
or false in case of an error
if you inserted and there were 0 affected rows, or the result is false or there's no inserted id, then it failed
ill check for the error
it shouldn't be too hard
looks pretty clean
not yet
$successfullyAddedUser = false;
<-- this variable is useless
this doesn't do what you think it does
also, you aren't checking this in the proper place anyways
if ($stmt == false)
<-- if this is true
$stmt->execute([ ... ])
<-- this will throw an error because you can't access a falsy value as an objecthmm ok
if ($stmt == false)
<-- this is just the same as if (!$stmt)
but may be confused with if ($stmt === false)
unless you want to check if the value is specifically false
, it's best to avoid if ($stmt == false)
the variable is set to false though
but i see
if it is set to false, something wrong happened
$successfullyAddedUser
<-- remove this, it's absolutely useless
it only makes the code more bloated
returning the value directly is a lot better than bloating with long variablesok
so it returns an int or false
ill just return the $stmt
or could just make it void
this is how i would write it
fixed it for the highlighting
i probably broke the language name
but you wanna know something?
this function doesn't belong in this class
but that's an issue for another time
which one?
addNewUSER
yes
you should follow the single responsibility principle
well where should it go
on a class to manage users
I just have a user class in models
currently
for now, what you have is fine
yeah id have to remove pdo code because you shouldnt have pdo stuff in models
unless you can
im still kinda learning the "setup" for php code
following their mvc approach
yeah, i know what you mean
code is updated and pushed to github
but first, lets make it work
ok so in register.php
i removed the addNewUser stuff
just got errors
you shouldn't have moved yet
you don't have any interfaces to access the database
basically, the database class is a closed system
ok
guess that's next
making that interface will be last thing i do for night
then you will have to make a plan on what the class does
well I got two models already one for user and one for task
that doesn't say what the database class needs to do
database should only add users, remove users, add tasks, remove tasks, update users, update tasks
basically CRUD
that's not right
the database should only care about database
adding users, removing users, adding tasks, removing tanks, updating users, updating tanks ...
that's all stuff for the controller
oh right
i forgot about the controller 😄
yeah i need to do a little MVC studying tomorrow then get back to this
i think that that's a good idea
Database should really just connect
connect and do query stuff
so i need a database interface?
that class is the "interface"
wait dont we need a __destruct for database
no, it disconnects at the end of the script
so i guess next then is controllers?
that's going to be a big re-write, but yes
yeah too late for that tonight
what am i missing to finish tonight
sleep
oh ok
good idea 🙂
i like that idea for myself too
rest well 🙂
thank you, i will
I think i only need one controller
because the user is interacting with it
i dont think user needs a controller
but I could be wrong
lots of code will have to interact with the user
I need to restructure my models
go for it then
yeah I read up on MVC last night
models should handle database stuff with the model then controller acts as the api to it
im not sure what roles a "user" has where as task is easy
it's just CRUD
a user can login, be created, deleted, edited, logout, be disabled
so similar?
depends
you need to communicate with the database in all those
so im starting with task because it seems easier
go for it
just do what sounds better to do first
so for list tasks
it should be
userid = $user
since it should be the user's useridthat depends on what you have
just Task.php and User.php for models
sounds good to me, i don't see any errors
so im bringing in the pdo to the model
NO! GOD NO, PLEASE DON'T
stop, now
that is bad in many levels
the database should be passed to the models via dependency injection
$this->__construct();
<-- ABSOLUTELY never do this in phpremoved the "extends Database" and removed the "$con = $this->__construct();"
good
let's do this right
since my approach is garbage
it's not about it being bad
it's about it completely shattering how oop works
maybe you could try to implement a trait that gives access to the database, but it is a really bad way too
guess i poorly designed this then 😄
mvc is always hard to design
I used to be better at it
gotta retrain myself
you can implement it using attributes, but i think you will have to use class reflection
so the approach you're suggesting is having the database being brought in as a parameter to the functions then called?
if im understanding that right
as a parameter of the constructor for the models, yes
or
all models automatically have a
$pdo
attributehmm either could work
i would go with the 2nd option
right not my models dont have a constructor
they don't need
make it a private pdo?
protected
you cant make it private
ok
sorry just the discussion in general made me really mad
had to step away a moment
right now database class just has the construct for pdo
create a model class for your models
like an abstract class?
yes
just like coreModel?
just
model
yup, something like that
ok so what are the important parts for this
the model needs to store a single instance of whatever you want to use
and pass to the models
probably the database?
yup, and other things
ok so in this case we can bring in the database and use the constructor to create the pdo object and have the other models borrow it as extends to base class mode?
model
that's the idea, yes
im kinda surprised i had like a mini flashback to oop topics in college
that's how it usually is
things will click soon
so I rememebered that you can't call functions statically without them being static so I called my database class this way instead of trying to do the construct method since it wasn't static then having to change all that code around
here's what I came up with
since Database class handles the connection, I have this could this setup the model using it
```php
<?php
namespace MD\models;
use MD\dbhelper\Database;
use PDOException;
abstract class Model {
protected $pdo;
public function construct() {
$pdo = new Database;
try {
$pdo->__construct();
} catch(PDOException $e) {
echo "Database could not connect: " . $e;
}
return $pdo;
}
}```
I remembered in Java that abstract classes were the base for the "Object" class and some of its methods that all classes use
then classes just inherit and extend the Object class
seems to be weird trying to call prepare
not able to access the PDO object from the database class
why are you calling the constructor twice?
Wasn't sure why I can't access the pdo object through the database class
yeah, but that's not how oop works
the constructor is called automatically, and you shouldn't call it manually
What should I change
never ever ever call a constructor manually, inless it is the constructor of the parent class
and even then, you only do it inside the constructor
I couldn't figure out how to reach the PDO object
I thought i had to call the constructor to get to it
you call the constructor when you use
new
Yeah but when I do
$pdo->
none of the PDO functions pop upbecause your
Database
class isn't an instance of PDO
Hmm
So how do I get to pdo since it's used in database class
is it publicly accessible?
Private pdo variable
do you have a method to return it?
I even tried returning it in the constructor
It failed
constructors' return values are ignored
GitHub
PHPTodoApp/app/class/dbhelper/SQLConnection.php at main · MD-2016/P...
practice project to get back into php. Contribute to MD-2016/PHPTodoApp development by creating an account on GitHub.
i mean, your class only has an empty
connect
method and a non-public select
method
you should only see the connect
methodYeah I added those to work on tomorrow since I got too tired and a headache
you should rest
So setup basic database stuff in Database class, then have Model constructor call database then use the methods from database through Model on the User and Task models?
basically, yes
Hey I had a smart moment (:
you did
you just need somewhere to store your instances of the classes
Yeah pretty much
After those are done I can work on controllers which should basically just pull the model commands then act as the api to the view to display
yup
and will you write the views in php?
Hmm
Well the login and register both need php code to function and the user page will pull from the database
Most likely
makes perfect sense, and is the easiest anyways
I guess if I made an about page or if I had pages for like 404 or something I could make them html
Oh! After models and controllers are done, I need to make a router
shouldn't the router be first?
Technically yes
I just didn't think about til just now
yeah, you should think about it then
so i removed the code from the construct and put it in the connect() and made the connect static
i have a much better idea for you
how about you create the
$pdo
in the __construct?
and store it in a static private variable?if the static private variable is empty, you create a new pdo
if it isn't empty, you do nothing
don't return from __contruct
fixed
in the __construct, check if the static variable is empty before you create the pdo object
if !$pdo?
almost
that's a local variable, not static
it has to be instantiated before you can check if it is empty
unless you declare it globally first and instantiate it
not if you set it to null by default
or check with
empty
so i would check if (!empty($pdo))
almost
that's a local variable
you want to access a static variable
again
local variable
it won't work
mines at top of class
class variable
if(empty($pdo)) {
<-- this is a local variableself::
yes
so that $pdo declaration should be self::$pdo =
all
$pdo
inside that class, yesyup, that's it
so now there needs to be methods for select, update, create, and delete
yeah, you can write your own ones, to make it easier for you to do what you need
I think I should either take in an array or more variables because
ill need to see what is changing
you can accept a table, a list of rows and receive a list of values
you mean the table construct
that's mysql i think
what table construct?
why are you reading about mysql vendor-specific extensions when you're using pdo?
how you make a table?
you write the sql for it
like how you did before
good idea
but don't forget the basics, like select, insert, update, delete
this is a start so far
sadly the intellisense must be broke because it isn't picking up on the PDO functions
self::$pdo;
<-- why this?just pdo?
no, it's just there, doing nothing
mistake
was having trouble listing the PDO functions I could use
sadly they dont show up
intelephense is ass
it lists ALL THE FUNCTIONS because it's ass
but it's the best we have, so
you will only see the list of functions if you ... type a letter
I should make sure the $field is properly handled
it could be more than one
which means that ...?
probably need an array or spread operator?
an array
a WHERE in there is possible too
you can make it even easier
instead of 1 array and a string, you can do 1 string or 1 array
'table'
<-- would be equivalent to table.*
['table' => [...]]
<-- would be equivalent to selecting each field from that specific table🤣
no, i wish it was that simple
😦
well crap
😂
let me guess
I need to loop that $sql creation
depends on the values you receive
so what is wrong with that code
well, you're trying to use an array as a string
it should be a string array 😄
😂 dreams
js does that automatically
or there's another way
there's another way
you can generate 2 different queries
if it is a string, just the basic
select * from table
if it is an array, then you have to implode it in a may to make it proper sql table namesthat's absolutely much worse
since
func_get_args()
gets variable number of arguments from the functionyes, but that's horrible, trust me
just take 1 argument, and accept a string or array
also,
exec
doesn't return a stringyup
what's the type checker in php?
php
i mean function 😄
what do you mean?
like if query is array
is_array
ok
if you need to check what type something is, just use
is_<type>
can use
implode
it's not a matter of "can", but it's a "use
implode
or build it yourself in a worse way"
which is something common in phpwoo
this means
loop to get the statements in the sql
hmm
so
how does this work
how about you stop and write a list of what you want the function to do?
like how you did before?
i got it 🙂
no, not yet
just make the list, trust me
point 2, the print part
that's absolutely horrible
don't do that
throw an exception
point 3, 2nd line is literally impossiible
impossible
as well as 4
list didnt help me then
yes it did
trust me, it always does
point 2 is fixed
why an error exception when an argument count (https://www.php.net/manual/en/class.argumentcounterror.php) would probably more appropriate?
i was going by this
or a value error: https://www.php.net/manual/en/class.valueerror.php
remember im not this well versed in php
i barely ever used php
in life
java is probably the only language ive used extensively
i know, but im asking this so you stop and think
okay changed to value error
so point 2 is fixed
and the other one?
im not sure
that's this code
return an array
databases dont return a single string
how
by just fetching
or a generator
ok
by the way,
exec
doesn't exist
https://www.php.net/manual/en/pdostatement.execute.php <-- it's execute
look at the return values as wellhere's some progress
it is some progress, but that's still not going to work
first, you're nesting too much
and your indentation needs serious work, asap
fix those 2 things
then, worry about making the string type work
completely ignore arrays for now
im not really concerned about indentation
that can be fixed after code is working
right now this needs to work
well, you have to have good habits
well indented code is mandatory
amazon didnt care
they were just happy it worked
it helps you catch bugs, it helps others to read the code
it highlights the conditions a lot more visibly
you can quickly glance at the code and understand how many levels deep you're getting into
so, please, fix your indentation
any fast way in vscode
i dont wanna do this forever
yes: use tabs
you can convert the indentation to tabs and it fixes everything for you
better?
much better
ok back to more important matters
^ you have a bug
fixed
can you show the fixed code?
yup
but delete the
$type
variableok
whenever I tried to use
is_string
in an if vscode complained it was syntax errored
well oddly it didnt this time
weird
this next
instead of fetchall, try a generator
basically, loop and
yield
ok
try it, see how it feels for you
sorry cat was frustrating me
generator looks too complicated
dude, it's literally a fake array
you get the values with a foreach loop
you replace the
return
with yield
ok so how would this work after my execute
that's literally it
no way
their examples are just foreach and for loops lol
that's all you need
this way, the select method returns a generator
and you just use a foreach on it
dinner break
looks good to mne
me
what do I do with the yield
since we were returning an array?
yield yields a value, and waits for you to use the generator to actually give you the value
so, imagine you return 500 rows
so add the value to an array?
instead of giving you a massive array of 500 rows, it gives you 1 row at a time
and then you do whatever you want
you can loop it and show it imediately
oh since this isn't the right class for it
where should it go?
i never said it wasn't the right class
im just saying that a yield is like a return, but waits for you to use the value
instead of an array, it gives a generator
that's what I got so far
so I can return the yield or function?
it's not a return, it's not a function
it's a yield
oh ok so id just call the function to use it?
then use a for loop to use it later?
check line 13 of the code
i see it
that's extremely useful because it doesn't "return" a value until you iterate the generator
so, it will wait until the value is needed
so far that while loop Id do just what you did
yup
do i say $row as $value?
you actually don't do anything else
once you yield, the function stops
ok since i got a meetup with a friend in a few lets aim to finish select for tonight
remove the for each, and you have 70% done
you see where im at currently for the array
it's rmeoved
removed
by the way, instead of calling it
$query
, i would give it a descriptive name, like $table
fixed
`
so we know select is the first word
ok
so
my guess is you would implode the array first then add it to the sql statement?
we would implode based on " "
space beng the separator
backtick, comma, backtick
you have to have backticks on the value as well
updated
then do the generator?
updated function
it's still missing something from the array one, but it's fine for now
now, move everything that's duplicated out
all of it off of the conditions
this are duplicated
the sql statements are a bit different
the loop is duplicated too
111php
moved out for now
to the bottom of the function
code is executed from top to bottom
i just moved it for now
i commented it out
why did you comment it out?
so i dont lose it
until this part is done then delete it
can you send what you have?
why did you comment it out?
you just have it in the wrong place
that's all
because i have no clue what were doing
so i dont want to lose working code
you see where the repeated code is, in this function?
there you go
now fix up the spacing
much better
whats next
rest
it's not done though
array feels like it's not done
it isn't
i just don't a good way for it
tomorrow ill tackle it next
then my goal for weekend is at least have database and model done and start on controllers
you can finish the other methods too, later on
im gonna have to start working at a faster pace
finish things sooner my turtle speed means no jobs for me
everybody learns at their own speed
i learn super quick, doing multiple things at the same time
not everybody is like that
im gonna have to get there because no one will hire me with this pace
you will get there
hope so
is there a solution to the array thing
yes
there are 2 solutions:
1-
['table', ['col1', 'col2', ... 'colx']]
2- ['table' => ['col1', 'col2', ... 'colx']]
oh neat! 🙂
you pick how it will work
ok
ok so back to the array
yes, which option will you choose?
both are good
but
maybe which ever is a bit easier
the 1st one
so I have the word SELECT already so I know it will be "column(s)" then FROM then either WHERE or not
ok let's do it
yup, the 2nd one is columns
and you know what to do with it
here's our starting point
on the
else
is where you generate the sql for the arrayyes
I have it somewhat started
yup, you do
so what is missing here
im guessing SQL statement is wrong
it's missing the table
and the variable is wrong
almost there
only other way off top of my head is to have table be broken up into $statements, and $parameters
that naming doesn't make sense, but i know what you mean
let's try an example
say we get
SELECT description FROM tasks WHERE userid=2;
using w3schools run editor
we get this
using example code...
what do you have in mind for when you call the function?
it should come out
SELECT
description FROM
tasks WHERE
userid=2;`
at least that's the goal
unfortunately discord doesn't handle it correctly because of how they handle backticks but you get the idea
so this
$table = implode(",
", $table);` is incorrecti get the idea
and it is incorrect, yes
but im trying to understand what you think that it will look like to do a select from this
they bring in an array of the commands words then implode it then create the query, prepare it then execute
write in code
or pseudocode
if you just use the space you get the right idea
then you add the backticks and comma after
imagine this
you have to use the
select
method
write, in pseudocode, how you would you call it (wrong or right, doesn't matter) and how you would process the result
imagine it's just a list of ids from the usersjust a general select works like this
must have keywords SELECT, FROM, and possibly where
that's not what i asked
well that approach isnt working for me
i need to understand how select actually works
im trying to understand how you think that the function is meant to work
there are two must have keywords and one optional then check for one or more columns and report an error if 0 are present, then you check for a table name after from being present or more than one then you check for WHERE clause and if there is then check the condition otherwise either an error or no WHERE clause was needed
so implode takes in an array and returns a string
so then you check the string out
unless you wanna loop through the array then implode
you can use
str_contains
to check for must needed words like SELECT and FROM
then WHERE is optional
after that you can check the inner workings where you look at the columns and suchcan you put all that into code or pseudo-code?
here's a start
but since there's a precise order they need to be in
what's that function for?
yeah, but why?
here's the correct logic
thing is there could extremely high number of columns (to the point of out of memory for the database)
so, i want to use your class to get data from the database
now, what do i do?
no clue
im just spinning my wheels now
it should be check for a connection, use the appropirate query method, then execute it
yes, so, i want to use the select method
now what?
it should create a proper string then pass it into an sql statement then prepare it then execute it
then yield the result for the caller
which arguments do i pass to the function?
key ones is SELECT, FROM with WHERE being optional
how would it look like in code?
well SELECT should be first element so
then columns after could be a ton so that's another array
imploding it with comma separators
then check
FROM
then array for tables
implode them with comma as separator
then check if the keyword WHERE is after them if not then it's done otherwise you check for the clause after the keyword WHERE and if it has something = something or whatever it could be
you would technically loop through the array until you reach the word FROM
when checking columnsi want to use your class to get a list of users' names and ids. how do i implement your class and the select method, in pseudo-code?
idk im just implementing select from scratch
but that's what you need to think about
you will use it
you're writting it
how do you want it to work?
that
is a start so far
so, you want to pass the query bits, one by one?
if you think about it if you're building a correct select query you need to check for SELECT first, then grab all the columns and parse them into something correctly formatted, then check for the FROM keyword then grab all the tables and format them, then check for the optional where keyword and if it exists then check for the conditions after
odds are im blowing this out of proportion
but im thinking in terms of "how do you make this from scratch"
im thinking of "i want to use this thing that md wrote. wth do i need to do to get my data?"
at this point idk
i there's
if there's an easier way I dont see it
there's no easier or harder way
there's what you want
well do you see an easy solution to this?
it feels like im basically recreating the SELECT method from scratch
which feels a bit too much for this scale of project
you're creating something, and im not sure what
idk either might just quit
or just think about it
do you want to write the queries manually all the time?
not really
but people can feed you the wrong info and cause trouble
how about you take the existing function and change it to take the name of the table and a list of columns?
ok?
how does this work exactly
$sql->select('users')
that's itno way
that's what you currently have
no! that's what you use to run that function
sorry epic im just not following on this problem
can you explain what im not seeing
i feel im doing way too much and this is just a todo app
not a SQL ORM
let's break the problem down
you don't need the
if
if you only receive a string from this
and the columns are the next argumentok
now we have this
$sql = "SELECT * FROM {$table}";
<-- just thisok
got it
now, the columns
so we would use a loop to check the columns til you hit the word FROM?
no!
you take an array with the name of the columns
how would you do that?
an implode
so
$columnNames = implode(" ", $table);
?it has to be proper sql
so just comma?
comma and backticks
backticks surrounding the comma?
wait
no, the backticks have to be around the column names
at least that does this
backtick, comma, backtick
got it
example of what it produces
using
$columnNames = implode("
,", $table);
almost there
what's next
yes backticks are there just discord problem
next, you need to implement that into the function
implement what?
removing things and formatting it?
friend wants to game may have to do this tomorrow
receiving the columns
What if I just do something like this
Make a generic setup then have the other specific ones call on it
i came up with this on my own
here's all ive done so far
as long as it works for you, but
$optionalWhere="",
in the select is absolutely uselessRight now setting up for testing isn't working
I may have to build a router
you do need one
Whenever I run it nothing happens
I even tried running a smaller scale todo app and all that happens is phpinfo displays in my console
because you need a router
I'll check Google
if you want to use an already built one, you can use klein
but there's more modern ones in packagist
Oh?
it makes things a lot easier
what's a good setup for apache to use php?
linux - any linux
well yes 🙂
but configuration side for it to work
the defauls work perfectly fine
creating a virtual host is one thing i know of
well see on nix I have to setup the config for it to work
likewise docker
yeah, that's something i don't know how to help you wish
i usually install debian, apache and php
then it's ready
yeah sadly i dont have that option
it's the easiest
you can try docker and just use the bitnami image
bitnami?
the vmware images
no, the docker images
yeah
which ones?
there's php, apache and mariadb
ok so bitnami php, and apache for my project
wait they use fpm php
so apache doesnt
apache can use fpm or modphp
oh cool
i prefer modphp because it's easier
Modphp
yes, it's a module for apache that runs php for you
gonna try getting apache working first so i can see it working then going move back to main todo app
I GOT IT TO WORK!!!!
apache is working!
test 1 worked and now we got the first error
Fatal error: Uncaught Error: Class "MD\controller\TodoController" not found in /var/www/html/app/view/todos/index.php:5 Stack trace: #0 {main} thrown in /var/www/html/app/view/todos/index.php on line 5
so does namespaces only work with the composer autloader?
@ἔρως I noticed that namespaces can be used with importing but it doesn't seem very concrete
issues with "finding files" come up often
guessing the layers to it aren't very big so mainly stuff in same folder