The values in the SitePoint example were not the same: the password file contained 1234568, while the PHP code compared against 12345678. The missing 7 is enough to produce a different digest. Hash functions operate on their actual input bytes, so check the strings being hashed before suspecting a PHP-version difference.
What caused the different hash outputs?
The SitePoint discussion eventually identified a typo: the file contained 1234568, but the hard-coded value was 12345678. Those are different strings, so a deterministic hash function produces different outputs for them. The original discussion is [Two same hash function with same values return different outputs].
This is not explained by PHP changing the result for identical input. The practical distinction is between the value you think you are hashing and the bytes the program actually passes to the hash function.
Inspect the input before debugging the hash
Print a quoted representation and the string length so that invisible characters and missing digits are easier to spot:
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
$file = fopen('passwords.txt', 'r');
$line = fgets($file);
var_dump($line, strlen($line));
var_dump(trim($line) === '12345678');
var_dump() shows the string representation and its length; the strict comparison reports whether the trimmed value exactly matches the expected string. In this example, if the file contains 1234568, trimming cannot add the missing 7.
Account for line endings deliberately
PHP’s fgets() reads a line and includes the newline in the returned string when it encounters one. The PHP manual describes the stopping rule: “Reading ends when length – 1 bytes have been read, or a newline (which is included in the return value), or an EOF (whichever comes first).” See PHP’s fgets() documentation.
Rank #2
If the file format defines one password per line and the line ending is only a delimiter, remove that ending intentionally before comparing or hashing. For example, trim($line) removes whitespace from both ends by default, but it does not remove characters in the middle or repair a typo. Its default removal set is documented in the PHP trim() manual. Do not use trimming automatically if leading or trailing spaces are meaningful in your input format.
Use password-specific APIs for account passwords
MD5 and SHA-1, including compositions that apply one digest after another, are general-purpose digest constructions—not encryption and not an appropriate new design for storing account passwords. Stacking digests does not provide the password-hashing properties intended by PHP’s password APIs or OWASP guidance. A classroom exercise or a legacy conversion task may have different constraints; for live credentials, use a password-hashing API.
For new password storage, PHP’s standard pattern is:
$hash = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($candidate, $hash)) {
// Password matches.
}
password_hash() creates a hash using a strong one-way algorithm, generates a random salt by default, and stores the algorithm, cost, and salt information in the resulting hash string. password_verify() checks a candidate against that string. Consult the PHP password_hash() documentation and PHP password_verify() documentation for the algorithms available to your PHP version and operational settings. PHP’s default algorithm may change as stronger options are added, so retain the complete generated hash rather than separating its components. OWASP’s Password Storage Cheat Sheet provides broader guidance on algorithm choice and work factors for deployment environments.
Quick Recap
Rank #4
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




