probably putting the server offline, removing the disk and accessing it in readonly mode from an OS that will not execute any of the code in that disk could be a starting point to backup what is still available.

It's important to make sure it cannot spread in your lan, through wifi or shared folders.

For the removal and recovering it depends on the version that affected your server, see if this helps: https://www.pcrisk.com/removal-guides/11217-amnesia-ransomware



The name is well defined, otherwise you would get an exception:

Route [navcolor] not defined.

The error message says Call to undefined function routes(), which in other words means that the function you are trying to call does not exists. Have you read the documentation? I posted the link for you in my previous message. You already have the solution, you could have solved this hours ago.



supposing you are not trying to load a user defined function named routes(), have you read the documentation? https://laravel.com/docs/5.5/routing#named-routes and the source in which this function should be defined? Does exists?

Use an editor that can autocomplete the code, in SublimeText for example, when you hover a method/function it shows you in which files this is defined and you can click it to see the code. Also add a linter plugin to enlight obvious mistypes and forgotten operators.


Whoops, now I see , sorry I was distracted by the null values. The redirect does not solve the problem, it just overrides. The warning happens because in your view the loop starts anyway and you are suppling a string when instead it expects an array or an object:

foreach ($result as $record):

Instead of $query->result() from the model return the object:

function read($where, $length, $start) {
    $this->db->limit($length, $start);
    return $this->db->get_where('myguestbook', $where);

this way you can cache it, use the custom result object and, in your controller, use the attached methods like num_rows():

$li = [];
$int = 0;
$template = '<li>user: %s<br>email: %s<hr></li>';

if(0 < $result->num_rows())
    foreach ($result as $record)
        $li[$int++] = sprintf($template, $record->user, $record->email);

$data['result'] = $li;
$data['result_count'] = $result->num_rows();

And in the view just run:

if(0 < $result_count)
    echo implode(PHP_EOL, $result);

    echo '<p>No record exists</p>';

Thanks to you for your reply, bye!


Hi Andris,

you may want to use SELECT ... INTO OUTFILE 'file_name_here' and perhaps use CONCAT() to create the query, if you do:

set @file = concat('/tmp/file_', UNIX_TIMESTAMP(), '.log');
select 'hello' into outfile @file;

It will not work, so you have to do:

set @file := concat("/tmp/file_", UNIX_TIMESTAMP(), ".log");
set @query := concat("select 'hello' into outfile '", @file, "'");
prepare stmt from @query;
execute stmt;
deallocate prepare stmt;

As suggested here:

But it's mandatory that the destination file does not exists, otherwise the query will fail, this is done to avoid overwriting files with random content. The alternative, if you want to append results, for example, is to use mysqldump or something like this:

mysql -uVAR -pVAR -e "SELECT 'hello';" > /tmp/random.log

To execute, if using PHP, from exec().

// Edit
But looking at previous answers, now I'm not sure is this you where searching for.



according to the source of the get_where() method in system/database/DB_query_builder.php, sending NULL is acceptable as it would skip to set the WHERE conditions. So looking at your code:

$data['result'] = $this->myguestbook_model->read(null, null, null);

It seems it should work fine. So, in order to debug, change the configuration so that it returns to you the last performed query: in application/config/database.php set save_queries to boolean TRUE, then go back to your model and right after line 3, i.e. where you perform the $query, write:

print $this->db->last_query();

And see what you get. Then try to run the query into a MySQL client and see if you get results. Once you end the debugging process set save_queries to FALSE again, as it slows down the execution of the code. Also, for a better debug process I suggest you to add Kint:

Can I ask why you are using CodeIgniter? It's for a new project or just maintaining legacy?


The code seems to be okay, are you sure opcache is disabled? If you are using PHP 7.0 then it's enabled by default, so if you ran the delete.php script and this was cached by the engine, then even after changing the code you still hit the cached version, until expiration, so while developing you can get an unexpected result. If this is the case you should disable it.


print var_dump(opcache_get_status());

To see the current status, it does not matter from which script you run it, if enabled, it will return the list of cached scripts


The above would not be an inline code, which is defined by backticks. Here you should use a code block, when you want to do such and you have other text above, then hit Return two times, so that you go to a new line and set a line of space between the text and the code. Hit TAB (or hit 4 spaces) and paste the code. If you are copying from your editor, then you can tab there, just make sure it equals at least at 4 spaces.

This textarea does not act like you would expect, so using the TAB key here does not focus on the next form element.

When the code is under 4 spaces then it's parsed as simple text.

At the end of the code block, if you want to insert other text, then again hit Return two times, otherwise there could be a parsing issue with the following text.

In alternative use the CODE button above, it will open a modal to paste the code.

For the XAMPP issue, see if the Apache error log gives information. Also, make sure the file has the .php extension.


Just to support rproffitt's, on Ubuntu 16.04 it redirects to 127::1:

ยป ping -c 3                                                                                       
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=64 time=0.055 ms
64 bytes from icmp_seq=2 ttl=64 time=0.029 ms
64 bytes from icmp_seq=3 ttl=64 time=0.048 ms

--- ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.029/0.044/0.055/0.011 ms

On Mac OS it fails:

$ ping -c 3
PING ( 56 data bytes
ping: sendto: No route to host
ping: sendto: No route to host
Request timeout for icmp_seq 0
ping: sendto: No route to host
Request timeout for icmp_seq 1
--- ping statistics ---
3 packets transmitted, 0 packets received, 100.0% packet loss
Votes + Comments
Thanks for the tests.

I just saw your reply, I'm glad you solved!

// Old answer

as far $permissions is defined by the input and defaulting to the database and not like an array:

$permissions = ((isset($_POST['permissions']) && $_POST['permissions'] != '')?sanitize($_POST['permissions']):$User['permissions']);

you can hardcode the options in the select tag, and then just compare which is set:

<select name="permissions">
    <option value="editor" <?php echo (0 == strcasecmp($permissions, 'editor')) ? ' selected="selected"' : ''; ?>>Editor</option>
    <option value="admin,editor" <?php echo (0 == strcasecmp($permissions, 'admin,editor')) ? ' selected="selected"' : ''; ?>>Admin,Editor</option>

For the sanitazation you could also write:

$permissions = filter_input(INPUT_POST, 'permissions', FILTER_SANITIZE_STRING) ? : $User['permissions'];

filter_input() will fail to FALSE or NULL if the filter fails or the input is not set, in both cases will fallback to $User['permission'], instead, it will return a string on success.

I usually manage selects through two functions:

if ( ! function_exists('_form_select'))
     * Create <select>
     * $array_options format:
     *  'option value' => 'text'
     * @param  string $name
     * @param  string $label
     * @param  array  $array_options
     * @param  string $selected
     * @return string
    function _form_select($name, $label, $array_options, $selected = FALSE)
        $template = '
        <label for="%1$s">%2$s</label>
        <select name="%1$s" id="%1$s">

        $options = '';

        foreach($array_options as $key => $value)
            $options .= _form_options($key, $value, $selected);        

        return sprintf($template, $name, $label, $options);

if ( ! function_exists('_form_options'))
     * Create <option>
     * @param  string  $key
     * @param  string  $value
     * @param  boolean $selected
     * @return string
    function _form_options($key, $value, $selected ...


you are trying to iterate the same result set two times: on line 28 and 106. On line 28 you get the first row, so if the query returns only one, you don't get anything when you call mysqli_fetch_assoc() again on line 106. You can use $User otherwise, if you need to loop again, insert data_seek() at line 105:

mysqli_data_seek($userResults, 0);

This will rewind the result set. Documentation:



if you don't want to allow duplicates then set a unique constraint to the brand column, and then use INSERT IGNORE ..., INSERT ... ON DUPLICATE KEY UPDATE ... or a regular update query. An example:

create table `brands` (
  `id` int unsigned auto_increment primary key,
  `brand` varchar(100) unique not null
) engine = innodb;

insert into `brands` (`brand`) values('sony'),('canon'),('nikon'),('fuji'),('pentax'),('zeiss');

> select * from `brands` order by `id`;
|   id | brand   |
|    1 | sony    |
|    2 | canon   |
|    3 | nikon   |
|    4 | fuji    |
|    5 | pentax  |
|    6 | zeiss   |
6 rows in set
Time: 0.003s

Now, if you try a regular insert, you get an error for duplicated entry:

> insert into `brands` (`brand`) values('Canon');
(1062, "Duplicate entry 'Canon' for key 'brand'")

If instead you use the INSERT ... ON DUPLICATE KEY UPDATE ... the existing row gets updated and your script can continue:

> insert into `brands` (`brand`) values('Canon') on duplicate key update `brand` = 'Canon';
> select * from `brands` order by `id`;

|   id | brand   |
|    1 | sony    |
|    2 | Canon   |
|    3 | nikon   |
|    4 | fuji    |
|    5 | pentax  |
|    6 | zeiss   |
6 rows in set
Time: 0.003s

What can happen? If in the edit form you select Canon id, and in the input field you write Zeiss, with this setup ...

Votes + Comments


that's a JSONP response, so in order to process this through PHP you need to remove the callback function that wraps the JSON data, for example:

callback({JSON DATA});

At this point you can remove it from the string:


$jsonp = 'callback({"name": "micheal"});';
$callb = 'callback'; // to remove

$s = substr($jsonp, mb_strlen($callb) + 1); // +1 to include the opening `(`
$s = substr($s, 0, -2); // -2 to remove `);`

print_r(json_decode($s, true));

Now, most JSON servers allows the client to define a callback in the requesting link:


So you receive:

foo({JSON DATA});

This allows you to write a more robust solution, as it's should not affect your script if they change their default callback function. See also if the server allows to get other formats, like simple JSON or XML.


However internalImageUpload() writes only to the database.

Instead, it's in:

imagejpeg($im, $upload_path.$filename);

I overlooked that, and yes by defining a second parameter you would save the resource loaded into $im. However you cannot inject (as far as I know) the contents from $_POST['image'] to $im.

Try something like this:


$uid      = $_POST['uid'];
$token    = $_POST['token'];
$group_id = $_POST['group_id'];
$needle   = $_POST['image'];
$haystack = 'data:image/png;base64,';
$png_blob = substr($needle, mb_stripos($needle, $haystack) + mb_strlen($haystack));

$upload_path = '../' . UPLOAD_PATH;
$filename    = time() . $uid . '.jpg';

// save to image folder
file_put_contents($upload_path . $filename, base64_decode($png_blob));

// save to database
internalImageUpload($uid, $filename, $group_id, FALSE);

$imageID       = internalGetUploadImage($uid, $filename);
$fullImagePath = BASE_URL . UPLOAD_PATH . $filename;

echo "<img src='".$fullImagePath."'  class='webcam_preview' id='".$imageID[0]->id."'/>";

Just make sure the path is correct, that ../ in $upload_path makes me nervous :D as it would always be relative to the link in the frontend side and to the system path in the backend side.


The point is that you cannot use $_POST['image'] that way. See the definition of imagecreatefrompng():

resource imagecreatefrompng ( string $filename )

It means it expects a string to define the filename, not the contents. Something that would work would be:

$im = imagecreatefrompng('file.png');

And from here you create a resource that will be saved into file.png, you cannot import the value of $_POST['image'] into this resource. The value in $_POST['image'] is a base64 encoded string, which once decoded is a binary blob.

Hence, you don't need that code to save the input.

For more details, take this part:

$image = $_POST['image'];
$filter_image = str_replace("data:image/png;base64,", "", $image);
// input is in format 1,2,3...|1,2,3...|...
if($filter_image == $invalid)
    $im = "";
    echo "false";
    $im = imagecreatetruecolor(320, 240);
    foreach (explode("|", $_POST['image']) as $y => $csv) {
        foreach (explode(";", $csv) as $x => $color) {
            imagesetpixel($im, $x, $y, $color);

the comment says the expected format is: 1,2,3...|1,2,3...|... but it is not like this, it is something like:


Which, decoded with my post.php script, produces a 10x10 cyan PNG image. Call it a.png.

The IF statement: if($filter_image == $invalid) is trying to compare an hardcoded blank blob to what is received by $_POST, to make sure it's not an empty snapshot. This can easily fail because the PNG specification allows to set a tIME value everytime the file is modified (or created), in practice some softwares as Gimp and in some cases ImageMagick, will add it and even ...


Okay, I got it to work, the JS function will export the canvas contents to PNG:


so, what you get in$_POST['image'] is a base64 encoded blob. All you need to do is to remove the data:image/png;base64, part, as you were doing, decode the remaining string and save it to a file, at basic:

$needle      = $_POST['image'];
$haystack    = 'data:image/png;base64,';
$png_blob    = substr($needle, mb_stripos($needle, $haystack) + mb_strlen($haystack));
$destination = __DIR__ . '/image.png';

file_put_contents($destination, base64_decode($png_blob));

So if $needle is data:image/png;base64,AAA..., $png_blob will be AAA. You don't need the GD functions unless you want to test if the resulting file is really a PNG and not a script.

Full test:

<!DOCTYPE html>

    <video id="player" width="480px" height="240px" autoplay="true"></video>
    <button id="takeSnap" class="startbutton messageButton">Take Snap</button>

    <div id="webcam">
        <input type="hidden" id="uploadvalues">
        <canvas id="snapshot"></canvas>
        <div id="webcam_preview"></div>

    <h3>Reload to see latest snapshot</h3>
    <img src="image.png">

    <script type="text/javascript" src="https://unpkg.com/jquery@3.2.1"></script>
    <script type="text/javascript">

        var captureButton = document.getElementById('takeSnap');
        var snapshot      = document.getElementById('snapshot');
        var video         = document.getElementById('player');

        // @see https://www.kirupa.com/html5/accessing_your_webcam_in_html5.htm

        navigator.getUserMedia  = navigator.getUserMedia
                               || navigator.webkitGetUserMedia
                               || navigator.mozGetUserMedia
                               || navigator.msGetUserMedia
                               || navigator.oGetUserMedia;

        if (navigator.getUserMedia)       
            navigator.getUserMedia({video: true}, handleVideo, videoError);

        function handleVideo(stream) {
            video.src = window.URL.createObjectURL(stream);

        function videoError(e) {
            // do something

        captureButton.addEventListener('click', function(e)
            var context = snapshot.getContext('2d');

            // Draw the video frame to the canvas.
            context.drawImage(player, 0, 0, snapshot.width, snapshot.height);

            //start webcam upload
            var webcamURL = 'post.php';

            $.post(webcamURL, {type: 'data', image: snapshot.toDataURL('image/png')}, function(data) {
                        var values = $('#uploadvalues').val();


                        var X = $('.webcam_preview').attr('id');

                        if ($.trim(values).length > 0)
                            var Z = X + ',' + values; ...
Votes + Comments
Nice work.
Going the extra mile, again :) +1

Hmm, what kind of input do you expect in $_POST['image']?

Because imagecreatefromjpeg() expects a string to be used like a file name. You are submitting $_POST['image'] instead, which it appears to be a base64 encoded string, and from the previous PHP code, it seems it should be a list of PNG image blobs.

At line 20 you have:

$filter_image = str_replace("data:image/png;base64,", "", $image);

But in the loop you refer again to $_POST['image'] so when you explode by the pipe and semi-colon chars, in practice you end up with:

$x[] = 'data:image/png';
$x[] = 'base64,HEX_STRING';

i.e. two strings that cannot be decoded by base64_decode() which, by the side, is not used in your code.

The imagesetpixel() function, instead expects an integer for the $color argument... and here I get lost because I don't understand anymore what should be the contents of $_POST['image'].


I got a message back from the provider and it's indeed not possible to edit the php,ini file because it's not only used by mine hosting package also by others. That kind of sucks!

Indeed, it sucks :| Not considering that they could use pools to provide separated resources and configuration files for each client.

I will ask if I can create a custom php.ini file in my own dcucment root to override settings.

Either that or my first suggestion: through prepended scripts, which should work for directives that can be applied at runtime, see:


Do you mean with a dedicated interface a thing like cPanel?

Yes. Sometimes you can edit configuration files only through these forms. You can, also, try to write a custom php.ini file and save it into the document root, success however depends on hosting configuration: if it is allowed then it will override the defaults.



Are you using PHP-FPM? In such cases the PHP engine can be located into another server and accessed through an IP address. The address is configured in the web server config files and the php.ini file is in the remote server. You can probably use ini_set() by including a script in top of the others. Through .htaccess this is done like this:

php_value auto_prepend_file "/path/to/iniset.php"

Otherwise in PHP:

require "/path/to/iniset.php";

I would also check with hosting documentation to see if you can set the directives through a dedicated interface.



if you can edit the main php.ini file, change the option to on:


then reload the phpinfo page to see if it applied. The location of the file is defined in the Configuration File (php.ini) Path of the phpinfo view. If you cannot edit the main php.ini, you can try to create a new php.ini file in the document root. And just add the options you want to change. The Loaded Configuration File field of the phpinfo view should show if the new file is loaded.

Note: some times, the configuration (of PHP or of the web server) does not allow to override the settings through custom php.ini files, so you may need to contact your hosting support to make changes.

For more info, see the HOST and PATH directives: