tl;dr: After testing thoroughly many combinations, it seems that the for
loop overwriting each character clears/changes the string contents in memory. Just be careful where the initial contents come from, it might still be present in those variables! See the update bellow.
Did some tests with PHP 5.6:
<?php
$cc = 'AAAABBBBCCCCDDDD';
#v1: unset($cc);
#v2: $cc=null;
#v3: for( $i=0; $i < strlen($cc); $i++ ) $cc[$i] = 'x';
sleep(500); // enough time for taking script pid and run the memory dump
?>
Tried each version of the above script (#v1 enabled, #v2 enabled, #v3 enabled);
Dump the memory of the process (see https://serverfault.com/a/408929/374467) and the 'AAAABBBBCCCCDDDD' string always shows up in the binary files generated (which contain the process memory). Also tested when $cc value is sent as a command line argument ($argv). Same result.
To date, I found NO reliable way to do this in PHP.
UPDATE
As suggested in the comments, using a string literal to initialize the variable might affect the results, as the literal might be held in memory. Thus I changed the script so that it takes an argument from cli and initializes the variable by applying str_rot13()
on it, making sure the contents of the variable are new. I also added gc_collect_cycles()
to force the garbage collection. So the test script looks like this:
<?php
$cc = str_rot13($argv[1]);
#v1: unset($cc);
#v2: $cc=null;
#v3: for( $i=0; $i < strlen($cc); $i++ ) $cc[$i] = 'x';
gc_collect_cycles();
sleep(120); // enough time for taking script pid and run the memory dump
echo "done \n";
?>
It seems that the first two methods (unset/null) won't clear the new value of $cc
from memory (even with gc_collect_cycles on) BUT the for
loop actually changes it! even if gc_collect_cycles is used or not.
Tested with PHP 7.2.20 (cli).
CAUTION You can still find the initial value of the argument ($argv) in memory!