The best think is to not reinvent the wheel. But, I understand, in PHP world it may be difficult to find a high quality component which already does that (even I'm pretty sure that the frameworks implement such things and their implementations are already tested, solid, code-reviewed, etc.)
If, for some reasons, you can't use a framework, here's some suggestions:
Security related suggestions
Use PBKDF2 or Bcrypt if you can. It's done for that.
Rationale: both algorithms can make the hashing process arbitrarily slow, which is exactly what you want when hashing passwords (quicker alternatives mean easier brute force). Ideally, you should adjust the parameters so that the process becomes slower and slower over time on same hardware, while new, faster hardware is released.
If you can't, at least don't use MD5/SHA1. Never. Forget about it. Use SHA512 instead, for example. Use salt too.
Rationale: MD5 and SHA1 are too fast. If the attacker has access to your database containing the hashes and has a (not even particularly) powerful machine, brute-forcing a password is fast and easy. If there are no salts, the chances that the attacker finds the actual password increases (which could make additional harm if the password was reused somewhere else).
In PHP 5.5.0 and later, use password_hash
and password_verify
.
Rationale: calling a function provided by the framework is easy, so the risk of making a mistake is reduced. With those two functions, you don't have to think about different parameters such as the hash. The first function returns a single string which can then be stored in the database. The second function uses this string for password verification.
Protect yourself from brute force. If the user submits a wrong password when she already submitted another wrong password 0.01 seconds ago, it's a good reason to block it. While human beings can type fast, they probably can't be that fast.
Another protection would be to set a per-hour failures limit. If the user submitted 3600 wrong passwords in an hour, 1 password per second, it's hard to believe that this is a legitimate user.
Rationale: if your passwords are hashed in an insecure way, brute force can be very effective. If passwords are stored safely, brute force is still wasting your server's resources and network bandwidth, causing lower performance for legitimate users. Brute force detection is not easy to develop and to get right, but for any but tiny system, it's totally worth it.
Don't ask your users to change their passwords every four weeks. This is extremely annoying and decreases security, since it encourages post-it-based security.
Rationale: the idea that forcing passwords to change every n weeks protects the system from brute force is wrong. Brute force attacks are usually successful within seconds, minutes, hours or days, which makes monthly password changes irrelevant. On the other hand, users are bad at remembering passwords. If, moreover, they need to change them, they will either attempt to use very simple passwords or just note their passwords on post-its.
Audit everything, every time. Store logons, but never store passwords in audit log. Make sure that the audit log cannot be modified (i.e. you can add data at the end, but not modify the existing data). Make sure that audit logs are subject to regular backup. Ideally, logs should be stored on a dedicated server with very restrictive accesses: if another server is hacked, the attacker will be unable to wipe out the logs to hide his presence (and the path taken during the attack).
Don't remember user credential in cookies, unless the user asks to do it (“Remember me” check box must be unchecked by default to avoid human error).
Ease of use suggestions
- Let the user remember the password if she wants to, even if most browsers are already this feature.
- Don't use Google approach when instead of asking for user name and password, the user is asked sometimes for password only, the user name being already displayed in a
<span/>
. Browsers can't fill the password field in this case (at least Firefox cannot do that), so it forces to logoff, then to logon with an ordinary form, filled by the browser.
- Don't use JavaScript-enabled popups for logon. It breaks browsers password-remember features (and sucks in all cases).
- Let the user enter either her user name or her mail address. When I register, sometimes the user name I want to enter is already taken, so I must invent a new one. I have all chances to forget this name in two hours.
- Always keep a link to "Forgot my password" feature near the logon form. Don't display it only when the user failed to log on: the user who don't remember her password at all have no idea that she must submit a wrong one in order to see the "Forgot my password" link.
- Don't use security by post-it.
- Don't invent stupid rules related to the password in order to make it weaker. Example: "Your password must start with a lowercase letter."; "Your password cannot contain spaces."
First off, gettext
is a good way to go, so don't dismiss if it doesn't sound easy at first; However there are other options as well that be useful to know. Before explaining that let's take a look at your suggestions first:
In your array
-way of doing this, you have a pretty much straightforward solution. The good thing is that you can store your translations in a data storage, then load it into your PHP script as an array, and that's it. However if you want to store your array statically in a PHP file, then editing it needs a) PHP programmer or an exprienced user who is familiar with the PHP syntax, just to edit the file b) syncing between even four or five different language files could be quite annoying and prone to errors.
What you need to consider here is: How can later add new elements to the language file? Can I leave it up to a translator or there should be a PHP programmer?
Your variable
-way of doing it is not practical. Why? I assume you will have couple of functions at least in your application, right? Then you need to pass all of these variables when you call the function, or you need to global
them. If you think you will have more than ten variables like this, then I strongly discourage you to do this. There might be name-conflict as well -- you can potentially override the value of another variable with the same name, however this could be solved by adding a prefix even as simple as a an underscore , so you will have $_welcome
for example. Anyways, if I were you I wouldn't think about it even; Don't do it.
One good way of doing it is to define Constants with a prefix. So for example in your en.lang.php
you will have something like define( 'LABEL_WELCOME', 'Welcome' );
and in your no.lang.php
you will have define ( 'LABEL_WELCOME', 'Velkommen' );
. The good thing about using constant instead of variables is that they're always available in your script. So you don't need to inject or global them. In comparison to both arrays and variables, they are faster because of the way PHP handles them -- they take up less space in the memory. The drawback is that you can't pass them to the translator, so again you need a PHP developer. Also syncing between files could be a bit of pain again.
The other option is to have a Function or Class/Method to retrieve the translation. It will be less efficient -- however I don't think you need that kinda of micro-optimization at all, but the added advantage is that you can apply a custom logic while retrieving the translation. For example imagine someday your beloved project manager comes to you asking if you could covert all of those texts to uppercase. You can't refuse to do it, so having a function in between could help you a lot when you need to apply/change a pattern to all of your translations.
To wrap it up:
Think about how translators can use it and come up with a working-KISS solution for them.
Think about how you can stay sync between different languages.
Think about if the same translation might be needed, let say for the mobile app. A cross platform solution could save your time. Don't dismiss JSON and ordinary Databases.
Think about how you can apply/change the logic when retrieving the translations.
Forgot about the performance. 99.9% of times you won't get that far to do micro-optimization like Constant vs. Variables vs. Function Calls. I assume your time as a developer/staff is more expensive rather than a processor time.
Update #1
My goodness, I post an answer for a year old question. Why no one is saying anything here? We need alerts for these cases.
Update #2
On the right side it says it's a year old question; However it's been asked two years ago! Everything is misleading here!
Best Answer
This is not a php-only issue, therefore there might be potential duplicate questions. Generally
The first approach (return count(...)) is faster to read and in some cases will produce faster code, because of the time consumed to instantiate the variable $count.
The second approach is kind of easier to debug and maintain. Each operations takes place in a distinct line, which is easier to isolate hence debug, since some IDEs can place a debug breakpoint to the exact line. It is also easier to maintain/extend in case you want for example to log the result or do another operation with this.
I do not believe there is a "better" way, or that it matters so much for a one/two liner. I would use the first one and then refactor it in case it had to be extended.
What many people would agree upon is that something like:
should better be broken into different lines.