douchun1859
douchun1859
2019-03-12 09:11

如何解析文件并使用数据解密另一个文件的数据?

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); 
}
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

2条回答

  • dongshan8194 dongshan8194 2年前

    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.

    my old solution

    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
    }
    
    点赞 6 评论 复制链接分享
  • dounong5373 dounong5373 2年前

    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.

    • Read both files, parse the encryption scheme, apply the replacements to the encrypted text

    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:

    • capture the substring before [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);
    }
    
    点赞 3 评论 复制链接分享