I try to replace characters in a loop, and I got a code like that
$my_file = 'encrypted_text.txt';
$handle = fopen($my_file, 'r');
$data = fread($handle,filesize($my_file));
echo "
".$data."
";
$file = fopen("encryption_scheme.txt", "r");
$members = array();
while (!feof($file))
{
$code = substr(fgets($file), strrpos(fgets($file), '=> ' )+1);
$code = str_replace('>', '', $code);
$code = str_replace(' ', '', $code);
$letter = substr(fgets($file), 0, 1);
$data = str_replace(',', ' ', $data);
$data = str_replace($code, $letter, $data);
}
echo $data;
fclose($file);
But instead of getting decrypted text it's repeating the codes like
631005,323151,810236,60916,384244,346538,404479
631005 323151 810236 60916 384244 346538 404479
Update
while (!feof($file))
{
$text = fgets($file);
$code = substr($text, strrpos($text, '=> ' )+1);
$code = str_replace('>', '', $code);
$code = str_replace(' ', '', $code);
$letter = substr($text, 0, 1);
$data = str_replace(',', ' ', $data);
$data = str_replace($code, $letter, $data);
}
your first problem is, that fgets
returns the text including the new line character (and depending on system carriage return).
your second problem is, that some of the "letters" are not "one character" in length (namely the unicode chars at the end).
your third problem is, that if the encryption scheme changes, you might experience unexpected results. let's say your encryption scheme is just this:
a => 1
b => 12
c => 2
the text 12
which clearly is b
would turn into ac
instead (because of order).
in my view, this leads to the conclusion, that mickmackusa's answer is the best one - specifically the second part of his answer, going through the ciphertext code by code.
I would probably use
$data = str_replace(',', ' ', $data); // do this once, not every iteration
while($text = fgets($file) { // fgets returns false on eof
list($letter, $code) = explode(' => ', $text, 2);
$code = trim($code); // <-- removes whitespace and new lines and so on
$data = str_replace($code, $letter, $data);
}
update:
// expand the text, if no "=>" is found:
while(...) {
if(strpos($text, '=>') === FALSE) {
$text = fgets($text);
}
if(!trim($text)) { // completely empty lines, even after expanding (EOF)
break;
}
// rest as before
}
I just tested this on my local host with your sample data.
The advantage of using preg_match_all()
here (although some people fear regex patterns) is that php doesn't have to 110x the battery of string replacements to achieve the result.
See the Regex pattern at work: https://regex101.com/r/HAQEuK/2
Code:
$encryption_scheme = file_get_contents('encryption_scheme.txt');
if (!preg_match_all('~(.*?) => (\d+)(?: *\R|$)~s', $encryption_scheme, $matches, PREG_SET_ORDER)) {
echo 'Failed to extract encryption scheme.';
} else {
$translator = array_combine(array_column($matches, 2), array_column($matches, 1));
$translator[','] = ' '; // replace commas with spaces
$encrypted_text = file_get_contents('encrypted_text.txt');
echo strtr($encrypted_text, $translator);
}
Output:
z C F I L O R
The regex pattern says:
[space] => [space]
, then capture the numeric substring in the same line, then match/consume the trailing spaces and line return (with the exception of the final line not having a line return to match).array_combine()
allows you to generate an associative array from the two columns of captured data.To be more accurate and prevent inadvertent replacements, you could process each integer individually and implode them after decrypting.
$encryption_scheme = file_get_contents('encryption_scheme.txt');
if (!preg_match_all('~(.*?) => (\d+)(?: *\R|$)~s', $encryption_scheme, $matches, PREG_SET_ORDER)) {
echo 'Failed to extract encryption scheme.';
} else {
$translator = array_combine(array_column($matches, 2), array_column($matches, 1));
$encrypted_text = file_get_contents('encrypted_text.txt');
$decrypted = [];
foreach (explode(',', $encrypted_text) as $integer) {
$decrypted = $translator[$integer] ?? $integer;
}
echo implode(' ', $decrypted);
}