2

Hi,

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:

<?php

$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:

http://url/page.php?callback=foo

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.

1

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:

<?php

$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.

0

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";
}
else
{
    $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:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQMAAAC3/F3+AAAABGdBTUEAAYagMeiWXwAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUA///+/v7eZjVAAAAAAWJLR0QB/wIt3gAAAAd0SU1FB+EIAQ0VMIC0C8gAAAALSURBVAjXY2DABwAAHgABboVHMgAAAABJRU5ErkJggg==

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 ...

3

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

snapshot.toDataURL('image/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>
<html>
<head>
    <title>Capture</title>
</head>
<body>

    <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>
    </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) {
                    if(data)
                    {
                        var values = $('#uploadvalues').val();

                        $('#webcam_preview').prepend(data);

                        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
0

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'].

0

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:

0

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.

0

Hi!

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.

1

Hi,

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

allow_url_fopen=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:

1

Hi,

you are missing a comma between these two columns, in the update statement:

work_carry = '$work_carry' demage_found = '$demage_found'

Then edit_customer_detail is not set by the form which, however, is okay if this is set by a previous step and carried through GET.

0

Yes, it's the same on tcpiputils: https://www.tcpiputils.com/browse/domain/stacychristine.com

And if you see the result of the WHOIS you can see who is the real registrant:

Registrant Name: CCA, Lt webPHOTOMaster, Betcha Private Registration

Which is:

It seems they developed the website, registered the godaddy DNS management for your client, then saved the website into Netsuite. If your client does not have the credentials to enter in Netsuite, then she can only ask to webPHOTOMaster support. I have some doubts you would be able to access that account. It will more probable that you could only point the DNS somewhere else, from godaddy panel, and start the website from zero. Good luck! :)

Besides: the hosting in use is powered by ASP.NET, not PHP:

> http head stacychristine.com                                                                   

HTTP/1.1 301 Moved Permanently
Cache-Control: private
Connection: keep-alive
Date: Tue, 30 May 2017 14:32:14 GMT
Location: http://www.stacychristine.com
Server: akka-http/10.0.0-100-netsuite-02
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
0

It seems godaddy was used to register and manage the DNS. Enter into the domain management page and see where it points. From those IPs you should be able to find the hosting company. The same can be done through tools like dig and whois:

> dig daniweb.com ANY

...
daniweb.com.        299 IN  A   198.23.117.137
...

> whois 198.23.117.137

...
Organization:   SoftLayer Technologies Inc. (SOFTL)
...

or through a service like:

for example, if you search daniweb.com you get a summary with the hosting company name:

Domain daniweb.com is listed in the top million list of Alexa ... This domain is hosted by SoftLayer Technologies Inc. (AS36351)...

Which is http://www.softlayer.com/

1

Hi,

at line 7 you have:

$update_id = $post_id;

while $post_id is initialized at line 68:

$post_id = $row_post['post_id'];

Which in practice depends on $edit_id defined at line 60:

$edit_id = $_GET['edit_post'];

So, it seems that you open the page like this:

page.php?edit_post=123

All you have to do is to initialize $edit_id on top, at line 4, so that is available to the POST conditional statement and to the other code.

Do not use $_GET directly, filter the variable:

$edit_id = filter_input(INPUT_GET, 'edit_post', FILTER_VALIDATE_INT, ['options' => ['default' => NULL]]);

Then replace:

$update_id = $post_id;

With:

$update_id = $edit_id;

Or simply adjust the following code to use $edit_id. Use the filter functions also for the other input coming from POST and GET requests, and use prepared statements too:

1

Hello Dani,

I don't think it's the user agent, I'm testing with Phantomjs and it uses this user agent:

Mozilla/5.0 (Unknown; Linux i686) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1

The testing script render.js:

var page   = require('webpage').create(),
    system = require('system'),
    vsize  = {width: 1280, height: 1024},
    address, output;

address = system.args[1];
output  = system.args[2];

page.viewportSize = vsize;
page.clipRect = {
  top: 0,
  left: 0,
  width: vsize.width,
  height: vsize.height
};

page.open(address, function() {
  page.render(output);
  phantom.exit();
});

Execution:

./phantomjs render.js LINK output.png

And it works fine. In this specific case Microsoft is rejecting HEAD requests, it allows GET requests, in fact, it returns 200, but the page has no contents because are loaded by Javascript: test with Postman to see how it renders. So, it seems it needs a rendering engine to show the contents.