Skip to main content
GameDev.net gamedev.net
🔒 Locked

Loading PNG In PHP And Returning It To C#

Started by Charabis Jan 9, 2012 at 10:43 PM 9 replies 3.8k views
Original Post
Charabis
Charabis
I'm working on a project that requires an array of textures. I'm looking to get the assets through PHP to avoid allowing direct access to them, but am having trouble getting them to return in a meaningful way. This is what I've built so far on the PHP side:


<?php
if(filter_has_var(INPUT_POST, "merchant") && filter_has_var(INPUT_POST, "test"))
{
$merchant = filter_input(INPUT_POST, "merchant", FILTER_SANITIZE_STRING);
$test = filter_input(INPUT_POST, "test", FILTER_SANITIZE_STRING);
}
else
{
die ("DataMissing");
}
$data_location = $_SERVER['DOCUMENT_ROOT'] . "/" . $merchant;
$arr = array();
if (is_dir($data_location))
{
$dir = opendir($data_location) or die("Couldn't access directory!");
while (($file = readdir($dir)) !== false)
{
$arr[] = file_get_contents($file);
}
echo $arr;
}
else
{
// Need to create it
mkdir($data_location, 0700) or die("Couldn't create " . $data_location);
echo "Empty";
}
?>


Creating the directory works fine, however I'm not seeming to get what I'd expect back to the C# program which calls it. In fact, with nothing in the folder, I seem to get back the string "Array". Needless to say, that's not what I expect or want!
My name is "Todd". Drop the "T" and it explains sooooooo much! :P
Deprecated
Deprecated
There is no [font=courier new,courier,monospace]to_str()[/font] method that will convert your array to readable data in PHP. If you want to display the content of an array (or any other object) you'll have to use [font=courier new,courier,monospace]print_r($mixed)[/font].

If you want your PHP script to output an image you could use the code below;

<?php
$file = 'creature.png';
header('Content-Type:image/png');
header('Content-Length: ' . filesize($file));
print(readfile($file))
?>


P.S It is very important that you do not output any kind of data (not even a newline, space or tab) anywhere else in the code. D.S
Those who can do, do; those who can't do, do teach.
Charabis
Charabis
I may not have said it quite the way I intended. let me clarify a bit more. I'm utilizing the Unity 3D game engine and need to get the PNG files into PHP and returned to C# as a byte array. The reason for needing this format is I intend to utilize "Texture2D.LoadImage()" to take the byte data and convert it into a Texture2D for display in the game. Sorry about the confusion
My name is "Todd". Drop the "T" and it explains sooooooo much! :P
Deprecated
Deprecated
Remember that your browser will interpret images and render them for you, instead of outputting the bytes they consist of. The code I posted will output the raw data from the image, meaning the bytes it consists of. I'm not sure whether or not C# [font=courier new,courier,monospace]Texture2D.LoadImage()[/font] accepts data containing the file-header, but unless you plan to output something that could be evaluated and parsed by C# I think you'll have to output the actual file.


$ lynx -source http://localhost:80/~username/gamedev.php

?PNG
?
IHDR2??? pHYs???o?d
OiCCPPhotoshop ICC profilex?SgTS?=???BK???Ko RB???&*! J?!??Q?EE?
...
Those who can do, do; those who can't do, do teach.
Charabis
Charabis
Excepting this has nothing to do with a browser I'm creating a PC/Mac standalone, not a web player application. Thus the need to figure out how to get a byte array to pass back to C# from PHP. It would be easy if "return" would actually work, but that doesn't seem to actually return anything to C#. Of course at the moment neither does the echo $arr
My name is "Todd". Drop the "T" and it explains sooooooo much! :P
Charabis
Charabis
Okay, seems there's a gotcha I wasn't aware of. I haven't confirmed 100% that the above works, but I was able to confirm that part of the code results in a bit of an oddity.


while (($file = readdir($dir)) !== false)
{
$arr[] = file_get_contents($file);
}

[/quote]

Detects 3 files even though only one is in the folder. The other two filenames it picks up are "." and "..". Wrapping the the line to load the file inside

if($file != "." && $file != "..")[/quote]

returns something that looks like it might be what I wanted. The size of the byte[] is about what I expected
My name is "Todd". Drop the "T" and it explains sooooooo much! :P
Deprecated
Deprecated
You're not understanding me... The code I posted will output a sequence of data that represents the image. Below are some examples on how to work with the above example in python. Although I haven't tested the code, in the first example, [font=courier new,courier,monospace]bytestream[/font] should be accepted by SFML as an image in memory.

1. To read the data as a stream of bytes in python

import urllib.request
bytestream = urllib.request.urlopen('http://localhost:80/~username/gamedev.php')


2. To read the data as an array of bytes in python

import urllib.request
bytearray = [c for c in urllib.request.urlopen('http://localhost:80/~username/gamedev.php').read()]


3. To read the data as a stream of bytes and save it to file in python

import urllib.request
open('image.png', 'wb').write(urllib.request.urlopen('http://localhost:80/~username/gamedev.php').read())
Those who can do, do; those who can't do, do teach.
Deprecated
Deprecated

Detects 3 files even though only one is in the folder. The other two filenames it picks up are "." and "..". Wrapping the the line to load the file inside


The symbolic links [font=courier new,courier,monospace].[/font] and [font=courier new,courier,monospace]..[/font] represents the current and the previous folder.

[font=courier new,courier,monospace]'C:\Program Files\.\.\.\..\Program Files\..'[/font] should place you in[font=courier new,courier,monospace][font=arial,helvetica,sans-serif] [/font]'C:\'[font=arial,helvetica,sans-serif], assuming that there is a directory called Program Files in your root.[/font][/font]


[font=courier new,courier,monospace][font=arial,helvetica,sans-serif]Edit: Added the quote I was responding to.[/font][/font]
Those who can do, do; those who can't do, do teach.
Charabis
Charabis
Ah. That's much shorter than trying to echo it, and gets the same results. Unfortunately, the results still don't seem to want to load as an image. Then too, there's the matter of returning it as an array of images regardless. At least this gets a good start on tomorrow. Thanks for the assist, Deprecated.
My name is "Todd". Drop the "T" and it explains sooooooo much! :P
Charabis
Charabis
Back to the problem early The size of the file is 4183 as reported by "filesize()" in PHP. Using Deprecated's suggestion of "print(readfile($data_location . "/" . $file));" returns a string to the C# script that's only 4040. Using my original method of "$arr[] = file_get_contents($data_location . "/" . $file);" and echoing element 0 (the one element in this test case), yields a string of size 4036. Can anyone explain why both of these are shorter than the number of bytes in the original file? I hadn't thought it would be so tricky to get a byte array into PHP and return it to the C# script that calls it, but that certainly seems to be the case.

Calling code and reporting result

WWWForm form = new WWWForm();
form.AddField("merchant", accountID);
form.AddField("test", testMode);

string result = sendData.StartSending(form, prepend + "get_images.php");

Debug.Log(result.Length);


PHP Code

<?php
if(filter_has_var(INPUT_POST, "merchant") && filter_has_var(INPUT_POST, "test"))
{
$merchant = filter_input(INPUT_POST, "merchant", FILTER_SANITIZE_STRING);
$test = filter_input(INPUT_POST, "test", FILTER_SANITIZE_STRING);
}
else
{
die ("DataMissing");
}
$data_location = $_SERVER['DOCUMENT_ROOT'] . "/" . $merchant;
$arr = array();
if (is_dir($data_location))
{
$dir = opendir($data_location) or die("Couldn't access directory!");
while (($file = readdir($dir)) !== false)
{
if($file != "." && $file != "..")
{
//print(readfile($data_location . "/" . $file));
$arr[] = file_get_contents($data_location . "/" . $file);
}
}

echo $arr[0];
closedir();
}
else
{
// Need to create it
mkdir($data_location, 0700) or die("Couldn't create " . $data_location);
echo "Empty";
}
?>
My name is "Todd". Drop the "T" and it explains sooooooo much! :P
Charabis
Charabis
Okay, it turns out the problem wasn't in any of the code I posted. StartSending uses Unity's WWW object to communicate with the server. I was still using the version I was using to pass XML around (WWW.text), which is not advised for binary data. That's what "WWW.bytes" is for >.<
My name is "Todd". Drop the "T" and it explains sooooooo much! :P

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.