|
|
|
|
|
|
|
|
PHP MYSQL DATABASE FULL MANAGEMENT CLASS SESSION INITIALIZER, MULTIPLE QUERIES, PROXY LOG IN, AUTHENTICATE AND REGISTER USERS
WITH ONE SINGLE METHOD, CHECK PRIVILEGES
version 1.5.5
|
|
A Php mySQL Database management class that can do all with one single method. You can issue your queries along with the same initialization arguments of the class, in one flushing line passing first the connection data (username, password, host etc.) and then your queries as a list or as an array or as a mix of both. Authenticate, register, reject, validate users throughout a session with one single method.
Featured also an interesting function that spots variable names conflicts within superglobals to detect possible malicious attempts to insinuate a variable by a superglobal different than the one allowed.
|
|
July 2004 |
|
{ @ }
|
|
|
|
|
WHAT BOOKS FORGET TO MENTION
|
|
A foreword to explain a web application database management that all books fail to account clearly for
|
This script has been completely revised on 2006-2007 but I cannot publish it online because the new version is used on a production website and its solutions must be considered reserved. Several issues that you may find have been corrected in the improved version. However it is still an excellent draft to work on, and the documentation has still much to say to a beginner.
Before I start describing this Php vs MySQL database class of mine, I will do what not many other scripters would do: I will quote and link what many would be afraid of quoting for they would regard it a "concurrent": another cool class developed by another developer that deals with Php vs MySql management - for developers must learn to cope with what most of them are unable to cope with, that is petty envy:
PHP Login System with Admin Features
I consider that class rather interesting though I have not written it and yet I am not afraid of linking it: which I was not supposed or obliged to do.
The definition of expert is elusive.
Most times, an expert is just a person who has been lucky enough to have been taught the things in the right way since the beginning, and since then assumes that whoever doesn't understand those things immediately and that way, must be an incompetent.
For when an expert is a person who has struggled alone to catch the meaning of something amidst the forest of signs meant to mislead you, he/she can no longer entertain whatever contempt for those who fail. A few seem really to assume that the semantic jungle we all live in is univocal. But it is not.
 A Louis Welden Hawkins painting, The Eiffel Tower as seen from The Trocadero |
There are those who learn things by route, and when one asks a question they point you out to the manuals. They don't understand that grasping the conceptual logics behind something is the furthest exact opposite of what a manual accounts and stands for.
They never wondered about the whys and the whereof's, they just do what it takes and since this is productive, they regard themselves as those who have undertook the professional path.
In the process that led them to be alleged or real professionals at the price of ceasing being empathic human persons, they learned how to dump sections of neural connections to empty the void with the raw data they must make room for.
The fact they never even realized there are contradictions within an affirmed procedure, and that they have accepted such procedure uncritically just like a believer would accept the Verb, is only a sign of how much disrespect they have been reared to nurture, while becoming professionals, for a human brain as it ought to be, in order to be elated only at the presence of a brain when it acts precisely as it is not supposed to be: by route and faith and without questioning.
I have a debt towards two persons that have been so kind to explain to me a few things about PHP web application database management. I am used to cite all acknowledgements I owe, also (if not especially) when I could have pretended I have none.
So let me thank here Pete and Rich from the yahoogroup PHP-List: they have helped me a lot to dig out the issue I am going to document soon below. And considered how much they have helped when compared to how miserably some italian groups failed at the same challenge (are you drowning? they throw at you a 1000 pages long manual that teaches you how to swim), they ended up stacking out their profiles as outstanding indeed.
Thank you guys, it would have probably taken me forever without you to understand what follows.
Why forever?
Well, I have here a lot of costly PHP books I've purchased mostly at Amazon.com. They are all, to say the least, terrific, extraordinarily good books.
So, this characteristic is exactly what makes all more surprising, because all these incredibly good books (let's be clear, no irony of any sort: if I don't like a book I just say it plain, so if I say they are good, you can read my lips comrade) invariably fail to explain how a database connection with authentication and registration of a new user must be done.
It is not that they do not cover the topic: it is that they cover it so extensively and in so confused a manner, that the main reason for which their books are normally acquired, namely to implement web applications, gets simply lost and you end up learning doing any sort of things with a database, except a web application.
Let me quote a few, to show the extent of this problem, and yet not before having added that I wish in my dreams I would have been able to write books like theirs - except for the chapters devoted to database interfaces.
- PHP and MySQL web development, by Laura Thomson and Luke Welling.
Probably the very best book out there, if we make an exception for the fairly advanced and amazing book by George Schlossnagle (my favorite).
- PHP 4 by Choi, Kent, Lea, Prasad, Ullman.
A perfect balance between a beginner's book and the details to make out of a beginner a valid PHP scripter and not just a lazy amateur.
- PHP 4.1 by Jeremy Allen and Charles Hornberger.
I found it at least as fantastic as the first book mentioned, yet you must know that it covers for each topic only one function -that perfectly carries out the task- but nearly neglecting the alternatives. Yet, not necessarily a bad procedure: it fits readers who want to get started as soon as possible and yet for the single procedure mentioned learn how to do all that is possible with it, taking out of it the maximum, and learning that one procedure in real depth.
Mentioning those, we're in heaven. It is just not possible to go higher.
Yet, none of them makes a beginner realize how to connect to a database by a web application. They all start discussing in such depth mySQL or anyway database connection authorizations, and how you can grant or revoke privileges for the connection to any user accordingly to the profile you want to ascribe to him/her (user entitled to all privileges, to select or insert data only etc... and so on discussing for dozens and dozens of page endless possible privileges combinations) that at no point they remember to stress clearly that all that has nothing to do with web applications for the internet, and that if what you do (and arguably that is exactly what you do!) are web applications, you won't have to use even one single line of those chapters devoted to explain privileges in your whole life.
If it weren't precisely as absurd as it sounds, I would have not been here spending so many lines. It is not that they first say to you how to do it for the web, and later they get deeper for those who may want to do more: they downright explain to you how to do more, without ever mentioning all that "more" is exactly what you'll never have to do even once when at building web applications.
 A Gustave Caillebotte painting, |
A web application has only one real member, even if your group lists one million of registered members. A web application has only one foo foo proxy member who does all the job on behalf of its subscribed and registered accounts (persons).
That is, inside your database you must have inserted sort of a superaccount, an all seeing superuser. And you do not insert even that by php! It must already be there: you must insert it creating it at the database administration console, and Php has just nothing to do with that stage.
Then, once you have that superaccount, you will never never never never in your whole whole whole whole life assign any any any any privilege whatsoever whatsoever whatsoever whatsoever to whomever whomever whomever whomever!
Perhaps this is not the right way at all to make it clear, but it is the way that comes out from one's exasperation when you finally understand that all the fights you have fought with hundreds of pages about assigning privileges had just plainly nothing to do with web applications.
You create the damned superuser at the console. To that you assign the privileges. Those, are the only privileges you will ever assign in your entire existence.
You create a database at the database administration console:
create database myCoolMembers;
You create a table to list the registered persons at the database administration console:
create table memberTable (username varchar(20), password varchar(20), email varchar(100));
Now you create the superuser at the database administration console:
Grant select, update, insert, delete on myCoolMembers.* to 'superboss'@'localhost' identified by 'ohThisPassIsABIGSecret';
When you use the statement
'superboss'@'localhost'
don't forget the single apexes around the username and the host name.
localhost is meant for a superuser that gets connected from inside the local machine and from nowhere else, whereas by an expression like (still with the apexes!):
'superboss'@'%'
is meant that this superuser with such username and password can connect also from a remote computer, even from the arctic sea if necessary, as long as it does it with the required username/password tuple (=~pair).
And that's all about privileges a web developer will ever use. He/She can learn more, but as long as he/she does internet applications (for intranet may differ being more tailored towards internal corporation issues) chances he/she will need more are as many as those of being lightstruck by Jove in person, namely rather scarce a commodity.
Also, by granting that way, mySQL takes care by itself to assign the correct data within the mysql.User and mysql.Db and mysql.tables_priv etc etc tables, so that all those immensely detailed descriptions in books about those tables and how you can manipulate them, just add confusion to confusion; because they never say to you you will arguably never have to add that data yourself and that a mere grant sql statement already takes care in the background to do all (all) that job for you.
Now, whenever an user logins, he/she tries that from a webpage. The webpage sends to a Php script the user data (arguably, username and password, inserted in html form fields) and the script logs inside the database not with such data! but the script logs inside the database with the superuser username and password, because it is and it must be (for security reasons) this superuser the unique script " dramatis persona" entitled to the privilege of handling and commanding a database connection and the further database manipulation that ensues.
And after this superuser has connected, it is still, still and forever, this connected superuser who delivers the query to check whether in the myCoolMembers database inside the memberTable there exists a user with that username and that password (and any other type of query, for that matter!) and if yes it delivers a session variable (or a cookie, ok) that says this user is valid throughout its browser session, or if the user is not recognized (mismatching username or password or both) either refuses the connection or (maybe first sending him/her to a registration page) inserts (by a database command sent through Php by, arguably, a call to the php built in mysql_query function) the new user's data so that he/she will be recognized next time.
And don't worry for the superuser: he can handle multiple tasks dispatching "holograms" of itself even if 100,000 surfers would require its services at the same instant: your php proxy is an efficient majordomo indeed (provided the server's processor, which is hardware and not " scriptware", allows).
But you just will never never never never grant privileges to no one else but that superuser whom you granted them to just once and for all - aside from the practical procedure you may want to change its password from time to time.
So what was all this talking about granting or revoking privileges by Php books aimed at if not at creating confusion describing a super-foetation of granting and revoking privileges details to guys who should apprehend them only at a second time, at best, and anyway surely only once the basic conception has been grasped in its cutting edge importance and discrimination?
Only once you have this clear in mind, a book should proceed to give you more details! Or tell you how. But what is the point with telling you how when you've not even understood what -and who- yet?
Perhaps I must mention one last thing.
When you log in your superuser to make it perform the tasks on behalf of, say, a surfer or of a registered member, you do that by connecting ( interfacing) the superuser to the database by a call, for instance, such as:
mysql_connect('localhost', 'superboss', 'ohThisPassIsABIGSecret');
Now, those terms, that is the username and the password of the superuser, should never be disseminated in cleartext in every php script of yours where the superuser is called in.
The fact PHP allows for such a thing to be potentially done is, in my very humble opinion, a mistake. Php should have not even made possible such a malpractice.
Anyway, since it is possible, you will be cautious and you will write in cleartext your superuser and password only in one php script, and you will always call
in this exclusive script by an include() statement, to read from there the password and username as assigned to variable names, and you will pass as arguments to your mysql_connect() statements the variables (not the cleartext!) that within the included file hold the cleartext values for the superuser's username and password; say the included exclusive script might just be, in its minimal form:
$THEBOSS='superboss';
$THE_SECRET_PASS='ohThisPassIsABIGSecret';
Then, whatever scripts requires the superuser would just do things like, in their minimal form indeed:
include('includes/mysecretFile.inc');
mysql_connect('localhost', $THEBOSS, $THE_SECRET_PASS);
 A Wilhelm Hammershoi painting, Interior with a Girl at the Clavier, 1901 Looks like a Magritte, doesn't it? |
And no, I couldn 't care less of being precise before the academic (or rather too often self appointed such) Php or scripting intelligentsia (whatever its spelling on your side of the pond) that stalks online and looks everybody upon down from a connected computer; because nothing is more important than being understood by the beginners rather than appreciated by the intelligentsia; because as Dostoevski (italian spelling) said: «this is not unworthy: for it is from the teenager that you make out the man.»
[The Adolescent]
and I prefer writing rather for those who have understood not than for those who think they have understood all already: the latter need nobody for the very valid reason they are also utterly unable to help out anybody, and would only be able to welcome teenagers with a kick in the ass for the simple reason they don't even know how to tell the difference between a caress and a kick - they have been made so much used to get the latter themselves, that they even forgot how the former looks like and what it could be for.
I am one of those used to kicks.
Only, I didn't anaesthetize myself so to bear them with a grin rather than sporting the necessary grim; and at the price of retaining my despicable ability to suffer, I can still spot the value of love and understanding as something that must be prized even though I never had much of that share.
Given the shortage, you may guess from this site I have decided to spread the latter, that needs it, rather than the former, that needs not being spread any further.
Internet groups become then not the forums where an occasion to help out and donate and feel yourself useful, or to divulge knowledge, may present itself; but they become the highway where prowling souls, lurking with gloating gazes, instantly seize the longed for occasion for bolstering their low self esteem (which has sound reasons to be such indeed) by kicking out whatever looked like kickable.
Needless to say, before such compulsion, everything comes very easily to look as one of such very same instances very soon: because you cannot give what you have not. And you just cannot see with eyes that sorrow succeeded in making completely obtuse.
USE OF THE SCRIPT AND ITS CODEX
|
|
General guidelines and the codes before the detailed description of the methods and inner variables
|
I will probably keep developing this class (its name: mysqlManager) over time. Consider ita version ready to be released to the public - not necessarily entirely bug free, but as in Saving Private Ryan they rhetorically wondered "when was the last time you felt sure about anything?" I could ask you: "when was the last time you installed a program that never showed up with a bug sooner or later?".
Let me first stress what this class does, for there are many other classes, arguably better than mine not that I am contending that, that deal with php mySQL database management.
This class has these somewhat "peculiar" features I like:
- You can issue all the SQL commands you want along with the initialization of the class instance itself, without calling in any other class method to do that.
That is, you initialize the class with its constructor, sort of say:
$proxy = new mysqlManager('host', $user, $pass, 'databasename', 0, 0, 0);
After the last arguments among the set of those mandatory as showed above, you can add as many optional arguments you want, all meant to be SQL queries string, and you can add them either as a list of strings or as an array of strings -each of them a mysql query statement- or a mix of lists and arrays both!
So, in one flushing line, you can handsomely and conveniently include all the commands for one set of tasks the proxy must do. This can help rationalize your code in a consistent manner. Of course, there are also methods that you can use to issue queries independently of the constructor, but what this class is particularly good at doing is allowing you to manage all the aspects of a database connection, interrogation and also of its relative session management and authentication data persistence, all with the usage of always the same one method. And I am not joking.
Also, given the way the class is structured, you can safely be induced to discriminate in your coding when you are starting the proxy (loggin the proxy in with its username and password) and when you're rather logging in a member: conceptual difference that is much less obvious than it may seem and which may well escape. Instance:
$proxy = new mysqlManager('host', $user, $pass, '', 0, 0, 0);
$proxy->mysqlManager('host' $VISITORusername, $VISITORpass, '', 0, 0, 0);
You may note how above upon initialization the proxy is first logged in with the initialization of the class instance itself:
$proxy=
and as later on it is called in again the same constructor but this round no longer to log in the proxy but to log in an hypothetic subscribed visitor (member).
There are not two methods for this: you can do all with nearly the very same syntax - you do not have to keep in mind ten different methods to put to work this class!
Thus the constructor is invoked anew, but this round no longer as an assignment, but as a call to the constructor now just handled as a method whatever as any other built in function of the just initialized $proxy class instance could be:
$proxy->
This is a smooth conceptual coding consequence of what we have discussed in the first part: the processes are analogous, actually in both cases the true protagonist of the story is the proxy, and the code rightly reflects this.
I think this might help a lot a beginner to discriminate and corroborate over time the conceptual grasping of the logics behind proxy logging
and subsequent (if any) surfer (member) authentication (or also registration if needed - which you can do as you'll see still using that very same syntax!).
The class understands from the fact it has been already initialized that any subsequent call to its constructor cannot be meant any longer to be for a proxy connection to the database but must be for checking a member's username on the designed table.
Constructor's Arguments
The signature of the class constructor (also if used as a method) implies the following arguments.
Please take a few minutes to review them, for they are important for understanding what the class is able to do with one method alone:
- $host: first argument, and it is the hostname to connect with.
- $user: the username that corresponds to the proxy (or to the member if you're using the constructor as a method).
- $password: the password that is used by the proxy (or member) to enter the SQL database.
Please note that this class will not store this sensitive data in any class variable, as nearly always all classes dealing with mySQL management do, thus avoiding the transmission of the password through the TCP/IP headers.
- $database: the name of the database the proxy wants to connect with.
Please note that:
- When you use the mysqlManager method as constructor, namely through the = symbol, this argument is the name of the database the proxy must connect with.
- When using this very same method no longer as a constructor but as a standard class method by the use of the -> symbol in order to authenticate a subscriber and not to log in the proxy which you have already logged in, then this argument must be the name of the SQL table (I repeat: the name of the table) where are stored the usernames and the passwords of your clients or subscribers.
- $autogetFingerprint: Once an user is authenticated, there is one thing that you may want: you may want to be sure that at whatever subsequent visited page (maybe within a pool of pages reserved to authenticated members) the authenticated visitor is still the same you authenticated at the earlier stage (page) and neither an interloping impersonator nor a non authenticated/authorized user that entered that page by merely knowing/bookmarking the web address.
If you want the class to perform this verification check, pass this argument as number 1 - and trust the class, for it makes a check that is not so easy to fool.
Of course, the class will achieve that because it will meddle with the session.
So it is paramount you keep in mind this: the class initializes a session by itself: do not, never, initialize a session yourself by session_start whenever you use this class: the class does it all by itself, and any second call to a session start would badly interfere with the class and would make the check of the fingerprint fail! And I mean it.
When using this class, put the signature of the class as the very first thing in your script, before any header is sent.
This is a class that will relieve you of a lot of work and concerns! Put it to work, and do not do the work it already does for instance by initializing sessions on your own.
If the user is found as not matching with the expected one (namely the class does not recognize it as previously authenticated - arguably at some previous web page), it performs a redirection to a variable named
$TO_LOGIN_PAGE
which you can still custom with a convenient address of a convenient file residing on your server. By default such variable carries no address, thus no redirection is performed, but a message of "Invalid session" gets printed.
If you initialize an instance of this class by passing to the constructor no argument at all namely just a thing as round and as simple as:
$proxy = new mysqlManager();
then no proxy is initialized, obviously enough (because you didn't pass any data!), and yet the check of the fingerprint will be performed! Yes!
Thus if you have authenticated an user at page zero and you do not need the proxy any longer at page one two and three, but you do want to be sure the user accessing those reserved pages is still the one you authenticated, then do pass this call to the constructor without argument, and that will do the trick, log no proxy that you need not, and yet it will still force non authenticated attempted connections to bounce back towards the shores of:
$TO_LOGIN_PAGE
What is important that you understand is that whichever way you elect to put in action the $autogetFingerprint tactics, this cannot be performed if you have not previously authenticated a subscriber: only second calls to second pages should be candidated to make use in either way of the fingerprint validity check: in fact you cannot verify the validity of a fingerprint if first you have not created one at some, say, page zero - and the creation of the fingerprint occurs only either upon successful authentication or successful registration.
In absence of a fingerprint, the page thus protected will refuse the connection (which is what you want).
Needless to add: only subscribers need authentication and subsequent identity checks: the proxy needs only being logged in and nothing else, because the proxy is, so to say, an "alias" of the server itself and makes no point verifying its identity at each page visited by a surfer: it is the surfer who is the potential alien, not the proxy, which is always a perennially and by default authentic(ated) dweller.
- $privilegeType: this argument defaults to zero and affects access privileges.
In order for it to work properly, also the previous argument $autogetFingerprint must be passed as 1.
Think of it: if you want to verify also the privileges in order to validate an access, you must obviously also instruct the function to verify the fingerprint. Makes sense. First verify the fingerprint (if that doesn't match, you won't even need to verify the privileges), if it matches you may instruct this second an d further verification of the privileges.
Privileges mean this: that some web pages must not be protected only against the access of non authorized members, but there are also pages that should discriminate among different degrees of access privileges among the members themselves.
Like in a army you are all soldiers (generals and privates alike), all entitled to enter the headquarters and all subject to the same esprit de corp, yet not everybody can have access to the classified dossiers too.
A typical example is a newsgroup moderator which is a member of the (news)group, of course, but should have access to certain group management pages to which, obviously, not all members should be allowed to access.
Thence the necessity to be able not only to verify whether a member is authenticated having provided the correct username/password pair to access the members' pages, but we may also need to verify whether for a given page (which we want to protect) there are no further restrictions that apply even to members.
To use this feature, namely to discriminate also among privileges, you must have in your mysql database a table, where the name of each user is stored and to each of such usernames is linked a field that carries a value representing the access power assigned to his/her membership or profile.
Provided you have such a table, and that it preferably resides in the database you use when logging in the proxy, all you have to do to use this features is to hard code (write, that is) in the class the values of the following class variables (you can locate them nearby on top of the class codex):
- $PRIVILEGES_TABLE: assign to it as a String the name of the table where such privilege profiles are stored. Defaults to "profiles_privileges"
Please do not give to this table exactly the name "privileges": it seems MySQL considers it sort of a reserved term (on my MYSQL it refused to crate such table claiming a non existant "syntax error").
- $PRIVILEGES_TABLE_FIELD_TO_CHECK: the field name where the username in such table is stored. Defaults to "username".
- $PRIVILEGES_TABLE_FIELD_TO_GET: the field name where the privilege type in such table is stored. Defaults to "privilege"
As for what the privilege type will be, it should be what normally is: a number, whereas the logics that this class implements is that the greater the number, the ampler the access: for instance number 0 has access only to pages of level 0, but number 4 has access to 0,1,2,3,4, whereas number 2 has access to 0,1,2 but not to 3,4.
The class verifies exactly that the browser that is accessing the protected page has been previously authenticated (is run by an authenticated surfer, that is) and then checks also on such table (if this argument is passed) whether the privileges for this username (username is stored in the class) are either equal or major to the number assigned to this argument.
If you want to assign the privileges too for a given user upon registration, it can be done too: just set the class variable
$AUTOSET_PRIVILEGES_ON_REGISTRATION
to 1, and it will be done: this argument will be assumed as the type of privilege to assign. For this to work, you must pass as 1 also the next argument dealt with named (see a few lines below) $registerIfNew.
Of course, it is still assumed that a privilege table as just outlined above exists, for it would be in such table that the newly registered members would get assigned their privileges.
So, if $AUTOSET_PRIVILEGES_ON_REGISTRATION is set as 1, upon registration also an entry for the newly registered user in the privileges table will be added, in the shape of a record where that username gets associated assigning to him/her the privilege number that you have hereby passed as argument $privilegeType.
- $registerIfNew: defaults to zero.
If passed as 1 implies that if upon using the method mysqlManager to verify the validity of an username/password set, the authentication fails, and therefore the user results not registered, the procedure to register it will be immediately activated by default without you having to meddle with it with any further scripting.
I signify by "registration procedure "that the provided username and password will be inserted in the aforementioned users SQL table; such table is described in the class variables (whose values you could custom):
-
var $tableName='members';
var $userFieldName='user';
var $passwordFieldName='password';
Once stored there, the next time these users login, they will be recognized and the they will be authenticated successfully without any need of further registration (even if $registerIfNew is passed as number 1).
If the username that has been provided appears as already taken when attempting the registration, the user is redirected to a page that you can define setting a value for the class variable named
$TO_ALREADY_TAKEN_USERNAME_PAGE
inserting it physically in the very same code of your class template: this because this type of features like redirections are likely to be lasting features/addresses in your server settings, and thus would have made little sense forcing you to specify all of them by passing arguments at every class instantiation!
- Here can follow as the method arguments all the SQL queries you prefer as subsequent arguments - either as list or as array, or as both.
I call this flexibility indeed.
If a query fails, the further queries possibly passed to the constructor/method will not be executed, to avoid conflicts. Needless to say only if the connection is successful an attempt to issue the passed queries will be made.
Like in the constructor, used either as such or as a standard method, you can issue a whole string of queries either as a list or as an array whose each entry is a query, so you can issue multiple queries as an array by using the class method (documented further on) named queries.
This has more relevance as a feature than you may think - and the fact the idea is a simple one, inscribes itself in the honoured tradition accordingly to which often (though not always) simple ideas deliver a windfall effect of benefits.
Imagine in fact that you have your database and your Php scripts that issue mysql_query statements. Now, you should always pass such queries as variables loaded from some included file: that is, I advise against writing queries downright in cleartext within mysql_query commands or the alike; this because if over time your database changes structure, whatever change in the structure would arguably require that you also change the queries that previously ran on the older database version; if then you have these queries written in one external file, you have to change then only that one file rather than opening also all of your php templates in order to change the queries in every single php script where you inserted them as cleartext.
Now, with the simple class option to pass your queries as an array too, if in a collection of queries meant to be executed as a logical chain you have to delete or add one or more queries because of changes in your database conception, you just add or remove entries from the array variable stored in an included file and passed to the queries class method. Without this class functionality, adding or removing queries would have arguably implied you would have ended up editing your php files too because adding a query to a php script that uses single query would necessarily imply that you'd have to add one more additional mysql_query statement in your php scripts too in order to accommodate the new query.
But with a class method meant to handle queries passed as arrays too, this problem is solved: each php file needs to use a call to the method only once: if then your queries increase or shrink in number, you just have to reflect that change in the array which includes the queries only, without meddling at all with the php files even if your queries increase or shrink in amount: to this class method you can just pass such array.
By the way an empty string as a passed query causes no error.
The class has a set of inner variables, called in upon errors (such as no such registered username and the alike...), all originally holding empty strings. Check the code, it is commented and the variable names are very explicative.
Yet if you change those variable empty values with urls, upon those error occurrences (say also failed authentication, bad query, no database connection, username name not found, wrong password) the class will redirect to those pages (details about these occurrences further on). So you can decide how to handle every single exception: by a full fledged set of redirections or by printing a custom error message or by just doing nothing.
A failure to log the proxy exits the script (see method logProxy).
It includes a couple of methods to detect variables conflicts. That is, you can check with a class method whether a variable name expected to arrive from, say, the http $_POST superglobal environment, conflicts with some same variable name sent in through some other superglobal environment (say $_GET).
In this way you can detect potential malicious attempts to insinuate "clones" through a superglobal meant not
to store that variable. The name of the method within the class which does this is: conflict (details further on).
The class can, if instructed, save in a variable a full history of the issued sql queries as query resources to fetch them all at a second moment!
To switch this feature on, as explained later on also in the table describing the available class variables, you just set the class variable named $STORE_QUERIES_IN_CLASS to number 1. You could switch that on on the run by a call like (though a bit weird, but perfectly valid):
$this->STORE_QUERIES_IN_CLASS=1;
The class is (version 1.3.0 upward) set to start sessions by itself, thus completely relieving you of any duty but those of initializing the proxy and then calling in again the constructor, but this time as a method, so to authenticate a member (if authentication is required and you don't need just the proxy of course).
By the way the auto started session, since version 1.5.0 also intializes in the session variable:
$_SESSION['proxy'];
an instance of the class itself, thus you will have its properties all available at each subsequent page as they were modified in the previous page.
Always include the signature of this class on top (=before anything else) of every page of yours where you want to use this class features (by include_once I guess).
Thus you must not initialize any session before this class. You must handle this class as something to do on top of everything else in your scripts, if you decide to use it: before headers are sent, and without starting any session before it. Starting a session might jeopardize the class a bit because the class creates a session id in such a way that each subsequent call to starting a session would generate a new session id, so that two pages in the same session could have two different ids. Let the class initialize the session!
The class has a feature such that if in your file X you have logged your proxy and authenticated a member (or registered and then authenticated it, which may be achieved with the very same two lines below) by, say:
$proxy = new mysqlManager('host', $user, $pass, 'databasename', 0, 0, 0);
$proxy->mysqlManager('host' $VISITORusername, $VISITORpass, 'membersTable', 0, 0, 1);
a fingerprint session variable has been initialized too in the background by the class itself, without you having to bother about it in the least.
This variable, let me repeat so to be sure you grasp the fundamental points better, performs as a fingerprint used to verify that the user who accesses possible subsequent protected area after the authentication, is still the authenticated one. Such fingerprint is elaborated following the security guidelines outlined at www.Php-mag.net.
If now you move, say by a page link, the authenticated member to a protected area, all you have to do to instruct this very same class to check that every access to that protected area belongs to a previously authenticated user is this: load in every protected page another time this same class and initialize one instance of it once again but this time by passing its 5th argument as number 1:
$proxy = new mysqlManager('host', $user, $pass, 'databasename', , 0, 0);
That fifth argument is the one named $autogetFingerprint.
That would do all, as far as membership protection (not yet with privileges concerns) is involved.
If conversely you want to protect the page and make it reserved to members and also to members with a specific set of privileges, say privilege level 3, this is the statement to include in your page:
$proxy = new mysqlManager('host', $user, $pass, 'databasename', , , 0);
Basically you just reiterate over and over the same commands with minimal variations, and the class does all the rest.
As already explained, also a call to the constructor without arguments, performs this check!
Now, finally, your full class code and later as last the description of all its internal variables and methods, with what they do and the arguments they accept.
 A Wassily Kandinsky painting |
| ");
}
};
return $result; //RETURNS FETCHED ARRAY
/*keep this comment to use freely
http://www.unitedscripters.com */}
#=================================================
# public - FETCH FROM ONE OR LIST OF QUERIES RESOURCES
#=================================================
function fetchQueries(){
$grab=( ! $this->FETCH_MODE)?'mysql_fetch_array':'mysql_fetch_assoc';
$output=array();
$offsets=array();
$offsetsCount=0;
for($a=0, $argsAmount=func_num_args(); $a<$argsAmount; $a++){
$anArg=func_get_arg($a);
if( is_array($anArg) ){
for($a2=0, $arrayItems=sizeof($anArg); $a2<$arrayItems; $a2++){
$anArg2=$anArg[$a2];
if(is_resource($anArg2)){
$offsets[]=$offsetsCount;
$entered=0;
while($row=$grab($anArg2)){
$entered=1;
$output[]=$row;
++$offsetsCount;
}
if(!$entered){array_pop($offsets);};
};
}
continue;
};
if(is_resource($anArg)){
$entered=0;
$offsets[]=$offsetsCount;
while($row=$grab($anArg)){
$entered=1;
$output[]=$row;
++$offsetsCount;
}
if(!$entered){array_pop($offsets);};
};
}
return array($output, $offsets);
/*example: $output[0][ $offsets[1] ] is the array of results for the second query passed as argument:
$returned_output=$foo->fetchQueries('QUERY RESOURCES');
$returned1=&$returned_output[0];
$returned2=&$returned_output[1];
print $returned1[ $returned2[2] ]['field_name_here']; */
/*keep this comment to use freely
http://www.unitedscripters.com */}
#=================================================
# public - SECURITY: CLEANUP OF INPUT DATA
#=================================================
function cleanup($inputString="", $onlyCheck=0){
$inputString=strip_tags(trim($inputString));
$inputString2=str_replace(
array('*', '--', '+', "'", '"', '?', '(', ')' ,'[' ,']' ,',', ';', '%', '/', '<', '>', '=', '!', '&'),
'',
$inputString
);
if(is_numeric($inputString)){$inputString=(integer)$inputString;};
if(is_numeric($inputString2)){$inputString2=(integer)$inputString2;};
return (!$onlyCheck)?$inputString2:($inputString2===$inputString);
}
/*Alias:*/function clean($inputString="", $onlyCheck=0){return $this>cleanup($inputString, $onlyCheck);}
#=================================================
# public - SECURITY: VERIFIES CONFLICTS BETWEEN VAR NAMES AND SUPERGLOBALS
#=================================================
function conflict($variableName=''){
$variableName=trim(str_replace('_','',$variableName));
$scopes=array('GLOBALS', '_GET', '_POST', '_COOKIE', '_SESSION', '_FILES', '_ENV', '_SERVER');/*if you change this order, change it in $objects below too!*/
$objects=array(&$GLOBALS, &$_GET, &$_POST, &$_COOKIE, &$_SESSION, &$_FILES, &$_ENV, &$_SERVER);/*if you change this order, change it in $scopes above too!*/
$flipped=array_flip($scopes);/*to spot the key from its value: "GLOBALS"=>0, "_GET"=>1 ... */
for($valid=1, $limit=func_num_args(); $valid<$limit; $valid++){
unset($scopes[$flipped[ strtoupper( trim(func_get_arg($valid)) ) ]]);/*dropped allowed domain, check non allowed only*/
}
unset($flipped); $output=array();
foreach($scopes as $key=>$value){/*loop $scopes not $objects: only on $scopes the allowed domains have been stripped. $key is a NUMBER*/
//uncomment the line below if you want to see what this does:
/* print("$value: "); foreach($objects[$key] as $k=>$v)print("$k=$v ");//*/
if(isset( $objects[$key][$variableName] )){ /*Conflict detected: report ONLY conflicting domain(s)*/
$output[]=$scopes[$key];
};
}
return (!sizeof($output))?false:$output;
/*keep this comment to use freely
http://www.unitedscripters.com */}
#=================================================
# public - RESET CONNECTION AND RESET VARS
#=================================================
function resetter($partial=0){
while(@mysql_close());
if(!$partial){
$this->PROXY_IS_LOGGED=0;
$this->QUERIES_RESOURCE_HISTORY=array();
};
}
#=================================================
# CHECK IF USER IS AUTHENTICATED - for session purposes/usage
#=================================================
function logged(){
/*you'd use the method get() for a solid verification: this method is useful only for those applications that want to keep track of a logged user but do NOT rely on member's only pages!*/
return ($this->authenticated_connection)?true:false;
}
/*alias*/function loggedMember(){return $this->logged();}
#=================================================
# CHECK IF THE PROXY IS AUTHENTICATED - for session purposes/usage
#=================================================
function loggedProxy(){
return ($this->PROXY_IS_LOGGED)?true:false;
}
#=================================================
# private - ERROR HANDLER: FAILED AUTHENTICATIONS, BAD QUERIES ...
#=================================================
function ERROR_REPORT($user='', $attemptType=0, $errorMessage='', $goToPage=''){
if($this->STORE_ERRORS_IN_CLASS){$this->ERRORS_HISTORY[]=$errorMessage;};
if($this->STORE_ERRORS_IN_FILE){
#============WRITE TO FILE============
$description=(!$attemptType)?$this->ERRORS_HISTORY[sizeof($this->ERRORS_HISTORY)-1]:'';
$f=@fopen($this->LOG_FILE, 'a+');
if($f){//file open successfully: write on it
$date=date('\t\tF d, Y;\n\t\tH:i:s;\n\t\tI; O');
$host1=gethostbyaddr($_SERVER['REMOTE_ADDR']);
$host2=gethostbyname($host1);
fwrite($f,
"||\n\n|\t $attemptType \n|\t\n\t\t$description\n\t\n|\t $user \n|\t\n$date\n\t\n|\t\n\t\t$host1;\n|\t\t$host2\n\t\n\n"
);
fclose($f);
};
};//written to file - if required.
$this->ERROR_CONSEQUENCE($goToPage, $errorMessage);
}
#=================================================
# private PRINT ERROR OR NAVIGATE TO FILE ON ERROR
#=================================================
function ERROR_CONSEQUENCE($goToPage="", $errorMessage){
$this->resetter();
$goToPage=( ! is_string($goToPage) ) ? 0 : preg_replace("/^\s+$/", '', $goToPage);
if($goToPage){
@header("Location: $goToPage"); return true;
}
else if ($this->PRINT_ERRORS){
/*comment out line below to PRINT nothing on error*/
print $this->ERRORS_HISTORY[ sizeof($this->ERRORS_HISTORY)-1 ].' '.$this->ERRORS_TABLE[$errorMessage].' ';
};
if($this->EXIT_ON_ERROR){exit;};
}
/*class end*//*keep this comment to use freely
http://www.unitedscripters.com */}
lines (with comments and blank lines):
 A Franz Xaver Winterhalter painting |
I remind you these guidelines:
-
The class has basically these syntaxes:
-
PROXY login
$proxy = new mysqlManager('host', $username, $password, 'databasename', 0, 0, 0);
This initializes a class instance and a proxy.
You could add as additional arguments a few SQL queries, if you wish so.
Beware: this statement alone will not start a session.
-
MEMBER authentication
$proxy->mysqlManager('host', $user2, $pass2, 'table name', 0, 0, 0);
This authenticates a visitor. It also creates a fingerprint if the authentication is successful.
If authenticated, this will start a session.
-
MEMBER authentication and registration
$proxy->mysqlManager('host', $user2, $pass2, 'table name', 0, 0, 1
);
This authenticates, or registers, or sends to an "already taken nickname page" the visitor. It also creates a fingerprint if the authentication or the registration is successful.
If authenticated or registered, this will start a session.
-
PAGE protection (with proxy login)
$proxy = new mysqlManager('host', $username, $password, 'databasename', 1, 0, 0);
This initializes a class instance and a proxy and checks whether there is a valid fingerprint created in a previous page where either syntax 2 or syntax 3 above was present.
If such fingerprint does not exists or doesn't match, it forbids access to the file and redirects to a login page.
Privileges considerations do not meddle here for the privilege level is set to zero.
Since the proxy is logged too, if the fingerprint is successfuly recognized you could add to the constructor as additional arguments a few SQL queries that will be executed, if you wish so, or you could invoke on the proxy the class public methods documented at bottom of this file, such as for instance:
$proxy->query('SELECT * FROM dunno_what');
The class has in fact also methods that you can use beyond the manifold things that you can achieve by just using the one "supermethod" mysqlManager (see bottom of file for the class public methods).
It's a very, very flexible class.
This will start a session.
-
PAGE protection also checking privileges
$proxy = new mysqlManager('host', $username, $password, 'databasename', 1, 2, 0);
This initializes a class instance and a proxy and checks whether there is a valid fingerprint created in a previous page where either syntax 2 or syntax 3 above was present and checks also that the previously authenticated user (valid fingerprint) meets also the further requirement of the privilege level (the yellow number requests a level 2 here).
If such fingerprint does not exists or doesn't match, or the privileges are not enough for the level set for this page, it forbids access to the file and redirects to a login page.
This will start a session.
-
PAGE protection (without proxy)
$proxy = new mysqlManager();
This initializes a class instance but logs in no proxy, yet it checks whether there is a valid fingerprint created in a previous page where either syntax 2 or syntax 3 above was present.
If such fingerprint does not exists or doesn't match, it forbids access to the file and redirects to a login page.
Of course, being passed no argument, it cannot verify the privilege level.
Since the proxy is not logged too, you cannot issue further queries: you just check the accessing user is still the previously authenticated and therefore authorized one.
This will start a session.
-
Brunt initialization
$proxy = new mysqlManager(1);
This will not start a session.
Passing one single parameter will initialize a class instance but will not check for the fingerprint - and also won't check for the privileges: in fact to perform such a check the database needs to be queried to scan the table where the privileges are stored, but in order to query a database table you need a valid proxy logged first, which can be done only passing the proxy data such as password etc etc, which is exactly what you do not pass using this syntax.
Yet, this can be useful in case you want to initialize a class instance and first change via script a class variable, then log in the proxy:
$proxy = new mysqlManager(1);
$proxy->some_class_variable='dunno what';
$proxy->mysqlManager('host', $username, $password, 'databasename', 0, 0, 0);
-
Proxy login and proxy authentication
If for some strange reason you want to login the proxy and also start a session fingerprint (just for the proxy):
$proxy = new mysqlManager('host', $username, $password, 'databasename', 0, 0, 0);/*this initializes the proxy as you already know*/
$proxy->set();
This starts a session for the proxy, namely also if no other user was authenticated.
Do not do this if later you authenticate a user too!
- You'd have another external file to include as well, which must be the only .inc file and the only file on your whole web project where the proxy username and passwords are written in cleartext (for as stressed, in my opinion sadly, Php requires you to write down in cleartext that sensitive data in a file potentially fit to be reached from a surfer if you're not cautious enough about where you store it - I would have preferred an approach that prescribed to store such data in a ciphered devise by default).
So your cleartext proxy username and password should be safely stored only once in a file and this file should be within such a directory from whence the server is instructed to allow calls to include but not to ftp file transfers or http folder access from... casual surfers! which potentially php would allow without even tampering in the way in any fashion if you're sluggish enough to forget about this mission critical security issue...
- If you want to include this class in a session so to retain all its values, you can.
Since the class initializes a session by itself, you may want to remember that each subsequently accessed php file would, yes, belong to the session but would also require to perform anew a proxy login database connection: that is, at each new visited page you have to log in the proxy again, for Php does allows you to save a class instance in a session but does not allow you to save database connections (resources) and share them throughout a session (unfortunately, in my humble personal opinion).
Also, you may want to rememer that to save classes in a session, the first thing you must load in your php file must be the class definition (this is a specific PHP thing, not a limitation of this specific class): after that you can interrogate your $_SESSION['proxy'] variable.
DESCRIPTION OF THE METHODS
|
|
The inner variables: how to custom them and the methods: what they do and the arguments they get
|
In this section I will detail about the methods and variables.
Yet bear in mind that though PHP 4 won't allow for methods signatures such as private protected public (though PHP 5 will, but presently upon writing this it has not been released yet), yet there are methods here which are private.
A private method can be defined as follows: a class method that cannot be invoked directly by any class instance (say $foo->amethod()) but which is meant to be run only internally by the class when the method class instances that are allowed to be directly called upon (so called public methods) are run.
So a few of these methods will be labeled as private. This means that no method I label as private should ever be used by calling it directly from a class instance ok? Being private their internal logics assume some other job is done which a direct call would arguably neglect.
An Alexandre Cabanel painting, The birth of Venus
|
CLASS VARIABLES |
|
$tableName $userFieldName $passwordFieldName
|
Custom those variables.
$tableName is the name of the member table upon which you want the proxy to check if a member name and password are a match or are included: defaults to "members".
$userFieldName and $passwordFieldName are respectively the SQL table field name where the username is stored, and the SQL table field name where the password for that username is stored.
The former defaults to "user", the latter to "password".
|
|
$CLASS_USERNAME
$AUTOGET_ FINGERPRINT
$SESSION_ FINGERPRINT_ FIELD_NAME
$AUTOSTART_ SESSION_IF_ AUTHENTICATED
$SESSION_ ANTI_INJECTION
|
$CLASS_USERNAME: will store in the class the logged username after a successful authentication or registration process.
$AUTOGET_FINGERPRINT: do not edit this manually.
If the autogetFingerprint argument passed to the constructor is, upon initialization, passed as number one, this class variable named $AUTOGET_FINGERPRINT is updated to the value of 1 too: this means all the pages that are protected, are instructed to check whether a fingerprint was produced, stored in the session, and whether the one exhibited by the surfer still corresponds, at each page change, to the one stored in the session: the pages achieve this by verifying if this class variable has been set to 1.
If the check fails and the fingerprint is not acknowledged, either a class warning is printed ("Invalid session"), or a redirection to the url possibly stored (typed, that is, in the very same signature of the class by you) in the other class variable named:
$TO_LOGIN_PAGE
gets performed.
That is, a failure to provide a recognized fingerprint while accessing a reserved area, makes the intruder bounce (back) to the page you may have specified in that class variable.
NOTE: if you think a fingerprint should be acknowledged but it is not, please make sure you're not starting any session yourself in your scripts: sessions, when using this class, should be started by this class itself exclusively, and starting more sessions for the same user, in the same page, would compromise the fingerprint!
$SESSION_FINGERPRINT_FIELD_NAME defaults to "identity". This is the $_SESSION['identity'] session variable where the fingerprint for the session will be stored. No need to change such name unless you fear a conflict between that name and any other session variable that you may have named after the same name for some reason.
$AUTOSTART_SESSION_IF_AUTHENTICATED: defaults to 1, and if a user is authenticated, it starts by default a session generating its relative fingerprint.
$SESSION_ANTI_INJECTION: defaults to a strange string. Do change it to some strange string of your own: it will be added (and ciphered by md5) to the fingerprint, thus adding significant anti injection security to it.
You can also change it periodically, say once in two months.
|
|
$AUTOSET_ PRIVILEGES_ON_ REGISTRATION
$PRIVILEGES_ TABLE
$PRIVILEGES_ TABLE_FIELD_ TO_CHECK
$PRIVILEGES_ TABLE_FIELD_ TO_GET
|
$AUTOSET_ PRIVILEGES_ON_ REGISTRATION defaults to zero. Set it as 1 and will also assign the passed mysqlManager method privilegeType argument to the user by setting an entry for him/her in the privileges table, upon registration.
$PRIVILEGES_TABLE: defaults to "profiles_privileges": the name of the table where you store, if any, the privileges settings for each user.
NOTE: do not name such table "privileges": MySQL might refuse creating or maybe even using the table (dunno why).
$PRIVILEGES_TABLE_FIELD_TO_CHECK: defaults to "username", the username field name in the privileges table.
$PRIVILEGES_TABLE_FIELD_TO_GET: defaults to "privilege", the privilege field name in the privileges table (by the way remember: the values held by such field with such name should be numbers representing the privilege degree/level).
|
|
$TO_LOGIN_PAGE (inside method: get)
$TO_CANNOT_ CONNECT_ PROXY_PAGE (inside method: logProxy)
$TO_REGISTRATION_ PAGE (inside method: verifyUsername)
$TO_ALREADY_ TAKEN_USERNAME_ PAGE (inside method: register)
$TO_RETRIEVE_ PASSWORD_ PAGE (inside method: verifyUsername)
$TO_FAILED_ REGISTRATION_ PAGE (inside method: register)
$TO_BAD_QUERY_ PAGE (inside method: query)
$TO_SUCCESSFUL_ REGISTRATION_ PAGE (inside method: register)
$TO_ INSUFFICIENT _PRIVILEGES _PAGE (inside method: get)
|
All these variables default to an empty string. Changing them to hold a url or a path to a server file, upon any occurrence in the class that invokes those variables, rather than either doing nothing or printing a message, the script will redirect to the specified page.
Of course, if such redirection occurs, whatever queued task in the current page will not be preformed because the page changes.
The redirection happens through a call to the php function header inside the method named ERROR_CONSEQUENCE.
Yet be warned that in Php the built in function header can dispatch to the given page only if nothing has been printed to the browser yet: this is why printing errors or relocation of the surfer to another file have been arranged as mutually exclusive options: if you decide to print, you can no longer relocate.
So be sure you have not issued yourself something (not even a mislooked whitespace either before or after your <?php ?> tags pair) to be printed to the browser, if you want to use this class redirections feature.
For the variable $TO_CANNOT_ CONNECT_ PROXY_PAGE you may want to have a look also to the description of the method named logProxy.
Also, maybe you want to consider, if you use these redirections, to set $TO_REGISTRATION_PAGE as the same as $TO_ALREADY_TAKEN_USERNAME_PAGE for if a username is taken you may want to present your audience with the option to register and choose a different nickname in the same web page. Nothing prevents you from assigning the same urls to those errors that you judge fit to be handled by the same error pages.
If a password is wrong but the username matches, that is a specific case correctly detected and arguably you'd prefer to handle it by $TO_RETRIEVE_ PASSWORD_PAGE.
|
|
$PRINT_ERRORS=1
$STORE_ERRORS_ IN_CLASS=1
$EXIT_ON_ERROR=1
$STORE_ERRORS_ IN_FILE=0
$LOG_FILE="log.html"
$ERRORS_TABLE
|
Custom those variables.
$PRINT_ERRORS defaults to printing error messages on the browser.
$STORE_ERRORS_IN_CLASS defaults to store the errors as an array of strings in a class variables named $ERRORS_HISTORY
$EXIT_ON_ERROR defaults to interrupt the whole script as soon as one query goes awry. Set it to zero to go on also if errors occur (this may produce multiple warnings drawn from $ERRORS_TABLE though).
$STORE_ERRORS_IN_FILE defaults to zero; if set to 1 opens a file and logs in it the errors with a few data about them in a simil-xml format.
$LOG_FILE defaults to the string "log.html"
Do change that! If the variable above is set to print errors in a file, such file will be named "log.html" and will default to be stored in the current webpage directory! So maybe you want to give that variable a full path (if you want to print on file).
$ERRORS_TABLE is an associative array. Do not change the keys, you can custom the values. In case you want to print errors rather than redirect the surfer to specific pages upon such occurrences, the errors are reported on the browser in the fashion they appear in this brief associative array. It is always a good idea not to report too much data about what the error was, so that potentially malicious surfers may not guess too much about the structure of your database.
|
|
$FETCH_MODE
$STORE_QUERIES_ IN_CLASS=0
$QUERIES_ RESOURCE_ HISTORY
|
$FETCH_MODE defaults to zero. If it is zero, when using the class methods fetchQuery or fetchQueries, the queries will be fetched using the PHP built in function mysql_fetch_array which will return the fetched sql table fields as an array indexed after numerical values and queried table fields names both.
If set as a number higher than zero, in order to fetch queries the class methods fetchQuery or fetchQueries will fetch the queries using the php built in function mysql_fetch_assoc which will return the queried sql fields as an array indexed only after the sql field names, namely without numerically indexed entries.
$STORE_QUERIES_IN_CLASS defaults to zero. If set to zero doesn't store queries. If set as 1, the class variables named:
- $QUERIES_RESOURCE_HISTORY
will hold as an array all the query resources (and not fetched strings) produced during the lifespan of the class.
If you decide to completely remove this because you consider it an "hazard", go inside the method named query and completely delete the conditional statement that checks whether:
if($this->STORE_QUERIES_IN_CLASS){ ... }
You can remove that conditional block safely and without looking after anything else, queries would no longer be stored no matter what value this class variable assumes.
Yet this functionality has been provided, and so can be switched on, because the mysqlManager method allows to execute in sequence as queries all the arguments passed after the last argument reported in its signature, so it is reasonable to assume that if they are passed and executed, there could be cases when you may also want to fetch their collective returned results at a second time, so they must be somewhere rather than being just executed in sequence and then irretrievably "lost" in case a few of them were mysql select query commands (which return data).
Yet, of course, there are also sql commands that return no data to be fetched (say insert) so deciding whether to switch the feature on or not depends arguably on the type of queries your current session is about to deliver.
Do not forget, if you want to change a class variable on the fly, you can obviously just say, assuming $proxy is an initialized instance of the class:
$proxy->STORE_QUERIES_IN_CLASS;
That's perfectly legitimate, it is not true that variables need a method to be set or read, that's just a Java custom to provide an additional method for that and/or for every class variable out there.
Of course, you remember that when addressing a variable from an instance, in PHP you omit the $ sign from the class variable name.
|
A Giotto painting
|
CLASS METHODS |
|
logProxy
|
I could have set it as private but eventually decided not so. It just logs in the proxy, a task already called in by the constructor (see further on).
The constructor calls this method in only once upon initialization of the class, not upon subsequent calls to the constructor meant as a mere class method.
Arguments:
- host: the proxy host, maybe 'localhost'
- user: the proxy username
- password: the proxy password
- database: the proxy database
- autogetFingerprint: to see what it does, please refer to the argument with the very same name in the next method named mysqlManager.
- privilegeType: the privilege type.
A failure to connect the proxy involves a call to the php keyword exit. Before that call to exit it is invoked $TO_CANNOT_CONNECT_PROXY_PAGE: if you set that variable value to an url rather than to the default empty string, it will redirect to a page for this bad exception (failure to log in the proxy, which is arguably an indispensable step).
A call to this method calls in also the minor class method named resetter: see that method too further on in this file.
|
|
mysqlManager
|
The constructor, which logs in the proxy upon initialization
$proxy = new mysqlManager(etc...);
and which just checks the members username and passwords if called in not as a constructor but as a normal method by an already previously initialized instance of the class, example:
$proxy->mysqlManager(etc...);
Arguments:
- host: the proxy or member host, maybe 'localhost'; members do not normally need it-
- user: the proxy or member username
- password: the proxy or member password
- database: the proxy database or the member table name if used a s a method.
- autogetFingerprint: this flags that this current class instance, on this such page, will not have to authenticate or register any user on any sql table, but will simply have to check the fingerprint (namely to check if a previous authentication exists) produced and stored in the session: if such fingerprint exists and matches the expected one, the surfer is allowed to view the page, otherwise is redirected to the TO_LOGIN_PAGE.
- privilegeType: passes the privilege type to the other private methods in case upon registration you set your class so to assign privileges too by setting the class variable $AUTOSET_PRIVILEGES_ON_REGISTRATION to 1, or anything which does not amount to false.
Yet it is mostly meant if you want to check not only the fingerprint but you also want to protect a page with a privilege degree too:
$proxy = new mysqlManager('host', $username, $password, 'databasename', 1, 2, 0);
This initializes a class instance and a proxy and checks whether there is a valid fingerprint created in a previous page where either syntax 2 or syntax 3 above was present and checks also that the previously authenticated user (valid fingerprint) meets also the further requirement of the privilege level (the yellow number requests a level 2 here). If such privilege level (in our example 2) is not found for the none the less validly authenticated user, it forbids access to the page.
- registerIfNew: if passed as 1 tries to register the new member if it sees it was not in the members table; of course it registers it if no names conflict occurs, whereupon an error is printed or a redirection occurs depending on how you have arranged the values of the class variables described above.
Perhaps this class seems particularly well inclined to accept as usernames email addresses.
- You can now add then as many queries, as strings, you prefer, either as a list or as arrays of queries or a mix: they would be all executed if nothing in the authentication process goes bad and as long as no error issuing a query is encountered (which would halt the elaboration of any queued subsequent query argument).
If you invoke this method without arguments, it will log in no proxy but it will check whether a session is authenticated: in this fashion a mere call to:
$proxy=new mysqlManager();
would allow you to protect members areas from unauthorized connections, without even having to log in a proxy - yet this protection does not account for privilege levels, for which you need the wider syntax:
$proxy=new mysqlManager('host', 'proxyname', 'proxypass', 'database', 1, 3, 0);
in that example the requested level is 3: to protect also checking privileges you need this syntax for it involves a proxy login, and a logged proxy is what is required in order to verify the privileges querying the privileges table in the database. So a logged proxy is needed.
|
|
authenticate
|
PRIVATE - you'd not invoke it by a class instance
It checks whether a member username and password are in the table (see class variable $tableName) and table username field (see class variable $userFieldName) and table password field (see class variable $passwordFieldName )
Arguments:
- user: the member username
- password: the member password
- table: the members table name
- registerIfNew: if passed as 1 tries to register the new member, of course if no names conflict occurs, whereupon an error is printed or a redirection occurs depending on how you have arranged the values of the class variables described above.
- privilegeType. You already know this.
|
|
verifyUsername
|
PRIVATE - you'd not invoke it by a class instance
If the authentication described just above fails (username or password do not match) this method seeks whether a username is already in the members table.
It can redirect to class variables:
$TO_RETRIEVE_PASSWORD_PAGE if the username exists - arguably it was a wrong password issue.
$TO_REGISTRATION_PAGE if the username doesn't even exist.
Can moreover register the new member if last argument registerIfNew was passed as 1.
Arguments:
- user: the member username
- password: the member password
- table: the members table name
- registerIfNew: if passed as 1 tries to register the member, of course if no names conflict occurs, whereupon an error is printed or a redirection occurs depending on how you have arranged the values of the class variables previously above.
- privilegeType. You already know this.
|
|
register
|
PRIVATE - you'd not invoke it by a class instance. Yet you could decide to use it and make it public.
If you chose to register it can trigger three redirections:
$TO_ALREADY_TAKEN_USERNAME_PAGE
$TO_FAILED_REGISTRATION_PAGE the latter if for some reason couldn't issue the query to insert the new username/password record in the designed table.
Such designed table name and user field name and password field name defaults to the ones set in the class variables $tableName, $userFieldName, $passwordFieldName.
If once inserted a record you need to include more data in the new user record, or in another table that hosts more details (I can have no clue about which they could be in your case, I can only guess the two basic ones: username, password), you'd just use queries, either as subsequent arguments passed upon invoking the constructor as a mere method (see above) or by using the method query or the method queries (see further on).
Arguments:
- user: the member username
- password: the member password
- table: the members table name
- privilegeType: if the class variable AUTOSET_PRIVILEGES_ON_REGISTRATION is set to 1, it will assign this newly registered user also a privilege (the number passed as privilegeType) in the privilege table.
The function will call in a class method named isBanned (see further on); such method is not currently implemented so unless you implement it, that will do nothing.
|
|
isBanned
|
Private. It is an empty method. It is called in before attempting a registration.
It takes in three arguments: username, password and the remote ip address.
By default it just returns false, thus it does not interfere. By returning true, it would prevent the registration.
Since checking whether a user is banned entirely relies upon highly specific criteria or utterly unknown checks on unknown (not to you, of course) SQL tables, it is up to you to fill in this method with the instructions that fit your own ban check criteria, of course if any.
|
|
makeid
|
Private. It produces a unique id of as many as 33 letters and numbers, and assigns it as the session identifier for this given user in this given browsing session. It produces this number by shuffling, randomizing, extracting, and adding a call to the php built in function uniqid.
|
|
get_privileges()
|
Private. Yet you could also use it as public (I did not include in this class method access signatures).
It returns the privilege of the user, which user(name), if this method gets used as a public method, should be passed as the only argument of this method.
If such argument is not passed, it is assumed that the class variable CLASS_USERNAME will be used.
|
|
set_privileges()
|
Private. Yet you could also use it as public (I did not include in this class method access signatures).
If used as a method, needs two arguments: the username and the privilegeType (the latter is arguably a number).
If it finds such user, it updates the field of its privilege type; if it finds no such user, it inserts a brand new record in the privilege profiles table.
|
|
set
|
Private. It initializes only once a fingerprint by concatenating:
- A session id of 33 letters
- The $_SERVER['HTTP_HOST'], which is probably good to avoid your php local scripts being probed or injected by copied pages of your website but residing on someone else's hard disk!
- The $_SERVER['HTTP_USER_AGENT']
- The $_SERVER['REMOTE_ADDR']
- The SESSION_ANTI_INJECTION class variable. It gives additional security that any attempt to simulate this script environment on a remote disk in order to connect later to yours (assuming this person knows you use this script) thus trying to inject something or to
| |