Jump to content
  • Advertisement
Sign in to follow this  
Carnevil_

Uploading/downloading replay files using mySQL?

This topic is 2522 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello!

In a game I'm working on, I'm trying to write a leaderboard system that allows you to submit/watch replay files. I am using a mySQL database to store the leaderboard entries, and use PHP files to query the database. Currently submitting/viewing scores works just fine, but there is no replay attached to the entries, which is what I would like to tackle next.

For starters, how do I coordinate a file transfer between the game and the server using PHP? I don't even know how to initiate it.

If this is in the wrong forum, then I apologize. It seemed like the best fit.

Thank you!

Share this post


Link to post
Share on other sites
Advertisement
The way to initialte a file transfer from PHP to a browser is to set the proper HTTP headers and simply echo the file contents. Perhaps you could do that with your game? Recieving files on the server is a little bit more involved on the client side, but is basically the same process.

Share this post


Link to post
Share on other sites
File contents is a FORM field, so you can submit it together with other data.
However, you can't use urlencoded form data for this; you have to use multipart/mixed.
If you google "HTTP file upload" then you get tutorials and specifications for both what it should look like on the wire, and for how to implement it in PHP.

Share this post


Link to post
Share on other sites
Thanks! I've gotten most of this working right. I have the downloading working correctly, but am having a bit of trouble getting uploading working correctly.

I think the main problem that I'm having is that I don't know what headers to include in my POST request. I've tried Googling around for the correct ones to include, but I haven't had a lot of luck.

Anyway, here's the code that I'm using. I'm guessing I need to fill in the INSERT HERE portion of the INTERNET_BUFFERS structure... but with what exactly?

Thanks!


HINTERNET hInternet;
HINTERNET hConnect;
HINTERNET hRequest;
INTERNET_BUFFERS Buffers;
DWORD dwNumBytesWritten;
DWORD dwNumBytesToWrite;
DWORD dwTotalBytesWritten;


// Get a handle for working with the Internet. If we can't connect, break
// out.
hInternet = InternetOpen( "<program name>", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if ( hInternet == NULL )
return ( false );

// Open an HTTP session for the site.
hConnect = InternetConnect( hInternet, "<server URL>", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, NULL );

// Open the POST request.
hRequest = HttpOpenRequest( hConnect, "POST", "<upload script>.php", NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0 );

// Initialize our buffers.
memset( &Buffers, 0, sizeof( INTERNET_BUFFERS ));
Buffers.dwStructSize = sizeof( INTERNET_BUFFERS );

// Send our HTTP request.
HttpSendRequestEx( hRequest, &Buffers, NULL, 0, NULL );

dwNumBytesWritten = 0;
dwTotalBytesWritten = 0;
while ( dwTotalBytesWritten < (DWORD)REPLAY_GetReplaySize( ))
{
dwNumBytesToWrite = min( 1024, REPLAY_GetReplaySize( ) - dwNumBytesWritten );
InternetWriteFile( hRequest, REPLAY_GetReplayData( ), dwNumBytesToWrite, &dwNumBytesWritten );
dwTotalBytesWritten += dwNumBytesWritten;
}

// Close our request now that we're done.
HttpEndRequest( hRequest, NULL, 0, 0 );

// Close our handle.
InternetCloseHandle( hRequest );
InternetCloseHandle( hConnect );

// Close our handle to the Internet.
InternetCloseHandle( hInternet );

Share this post


Link to post
Share on other sites
Is the problem that you don't know what the text of the headers and content should be? There's help for that: http://www.lmgtfy.com/?q=http+1.1+post+headers

Or is the problem that you don't know how to fill out proper INTERNET_BUFFERS structures to point at the proper data that you have constructed? There's help for that too: y http://www.lmgtfy.com/?q=INTERNET_BUFFERS+InternetWriteFile+msdn

If you still can't figure out how to structure your post text, and/or pass that text to InternetWriteFile, then you'll probably want to come back being a little more specific about what you've tried, what the documentation says, and exactly what the symptoms are of it not working.

Share this post


Link to post
Share on other sites
Alright, sorry, I meant to say that I wasn't sure what to fill in for lpcszHeader in the INTERNET_BUFFERS structure. I think I've got that figured out - though things still don't seem to be working.

First off, here's the revised code that I'm using:


HINTERNET hInternet;
HINTERNET hConnect;
HINTERNET hRequest;
INTERNET_BUFFERS Buffers;
DWORD dwNumBytesWritten;
DWORD dwNumBytesToWrite;
DWORD dwTotalBytesWritten;
char szHeaders[1024];

// Get a handle for working with the Internet. If we can't connect, break
// out.
hInternet = InternetOpen( "<program name>", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if ( hInternet == NULL )
return ( false );

// Open an HTTP session for the site.
hConnect = InternetConnect( hInternet, "<website URL>", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, NULL );

// Open the POST request.
hRequest = HttpOpenRequest( hConnect, "POST", "<upload script>.php", NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0 );

// Build our header.
sprintf_s( szHeaders, "User-Agent: <program name>\r\nContent-Type: multipart/mixed\r\nFilename: %s\r\nContent-Length: %d", "testfile.wrp", REPLAY_GetReplaySize( ));

// Initialize our buffers.
memset( &Buffers, 0, sizeof( INTERNET_BUFFERS ));
Buffers.dwStructSize = sizeof( INTERNET_BUFFERS );
Buffers.dwBufferTotal = 1;
Buffers.lpvBuffer = (void *)REPLAY_GetReplayData( );
Buffers.dwBufferLength = REPLAY_GetReplaySize( );
Buffers.dwHeadersTotal = 1;
Buffers.lpcszHeader = szHeaders;
Buffers.dwHeadersLength = strlen( szHeaders );

// Send our HTTP request.
HttpSendRequestEx( hRequest, &Buffers, NULL, 0, NULL );

dwNumBytesWritten = 0;
dwTotalBytesWritten = 0;
while ( dwTotalBytesWritten < (DWORD)REPLAY_GetReplaySize( ))
{
dwNumBytesToWrite = min( 1024, REPLAY_GetReplaySize( ) - dwNumBytesWritten );
InternetWriteFile( hRequest, REPLAY_GetReplayData( ), dwNumBytesToWrite, &dwNumBytesWritten );
dwTotalBytesWritten += dwNumBytesWritten;
}

// Close our request now that we're done.
HttpEndRequest( hRequest, NULL, 0, 0 );

// Close our handle.
InternetCloseHandle( hRequest );
InternetCloseHandle( hConnect );

// Close our handle to the Internet.
InternetCloseHandle( hInternet );


What's happening is that well, my file doesn't end up being uploaded. I have a PHP upload script that looks like this:

<?php
// Create the entry to put in the log.
$logEntry = date( "m/d/Y H:i:s" ) . "," . $_SERVER['REMOTE_ADDR'] . "\n";

// Write the entry to the log.
$file = fopen( "log.csv", 'a' ) or die( "can't open file" );
fwrite( $file, $logEntry );

if ( $_FILES["file"]["error"] > 0 )
{
fwrite( $file, "Return Code: " . $_FILES["file"]["error"] . "\n" );
}
else
{
fwrite( $file, "Upload: " . $_FILES["file"]["name"] . "\n" );
fwrite( $file, "Type: " . $_FILES["file"]["type"] . "\n" );
fwrite( $file, "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb\n" );
fwrite( $file, "Temp file: " . $_FILES["file"]["tmp_name"] . "\n" );

if ( file_exists( "upload/" . $_FILES["file"]["name"] ))
{
fwrite( $file, $_FILES["file"]["name"] . " already exists.\n" );
}
else
{
move_uploaded_file( $_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"] );
fwrite( $file, "Stored in: " . "upload/" . $_FILES["file"]["name"] . "\n" );
}
}

fclose( $file );
?>


... which produces the following:

01/08/2012 20:45:11,98.200.58.130
Upload:
Type:
Size: 0 Kb
Temp file:
already exists.


So, as you can see, the script is being run, but it appears to not have any information about the file being posted. I believe I have the headers set correctly as well as the INTERNET_BUFFERS structure setup correctly. I'm pretty stumped on what to try next as far as debugging this. It's not like I have return values or anything to work with. It just doesn't work and I'm not really sure why.

Anyway, any help would be greatly appreciated. Thanks!

Share this post


Link to post
Share on other sites
Alright, sorry, I meant to say that I wasn't sure what to fill in for lpcszHeader in the INTERNET_BUFFERS structure. I think I've got that figured out - though things still don't seem to be working. First off, here's the revised code that I'm using: HINTERNET hInternet; HINTERNET hConnect; HINTERNET hRequest; INTERNET_BUFFERS Buffers; DWORD dwNumBytesWritten; DWORD dwNumBytesToWrite; DWORD dwTotalBytesWritten; char szHeaders[1024]; // Get a handle for working with the Internet. If we can't connect, break // out. hInternet = InternetOpen( "", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 ); if ( hInternet == NULL ) return ( false ); // Open an HTTP session for the site. hConnect = InternetConnect( hInternet, "", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, NULL ); // Open the POST request. hRequest = HttpOpenRequest( hConnect, "POST", ".php", NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0 ); // Build our header. sprintf_s( szHeaders, "User-Agent: \r\nContent-Type: multipart/mixed\r\nFilename: %s\r\nContent-Length: %d", "testfile.wrp", REPLAY_GetReplaySize( )); // Initialize our buffers. memset( &Buffers, 0, sizeof( INTERNET_BUFFERS )); Buffers.dwStructSize = sizeof( INTERNET_BUFFERS ); Buffers.dwBufferTotal = 1; Buffers.lpvBuffer = (void *)REPLAY_GetReplayData( ); Buffers.dwBufferLength = REPLAY_GetReplaySize( ); Buffers.dwHeadersTotal = 1; Buffers.lpcszHeader = szHeaders; Buffers.dwHeadersLength = strlen( szHeaders ); // Send our HTTP request. HttpSendRequestEx( hRequest, &Buffers, NULL, 0, NULL ); dwNumBytesWritten = 0; dwTotalBytesWritten = 0; while ( dwTotalBytesWritten < (DWORD)REPLAY_GetReplaySize( )) { dwNumBytesToWrite = min( 1024, REPLAY_GetReplaySize( ) - dwNumBytesWritten ); InternetWriteFile( hRequest, REPLAY_GetReplayData( ), dwNumBytesToWrite, &dwNumBytesWritten ); dwTotalBytesWritten += dwNumBytesWritten; } // Close our request now that we're done. HttpEndRequest( hRequest, NULL, 0, 0 ); // Close our handle. InternetCloseHandle( hRequest ); InternetCloseHandle( hConnect ); // Close our handle to the Internet. InternetCloseHandle( hInternet ); What's happening is that well, my file doesn't end up being uploaded. I have a PHP upload script that looks like this: 0 ) { fwrite( $file, "Return Code: " . $_FILES["file"]["error"] . "\n" ); } else { fwrite( $file, "Upload: " . $_FILES["file"]["name"] . "\n" ); fwrite( $file, "Type: " . $_FILES["file"]["type"] . "\n" ); fwrite( $file, "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb\n" ); fwrite( $file, "Temp file: " . $_FILES["file"]["tmp_name"] . "\n" ); if ( file_exists( "upload/" . $_FILES["file"]["name"] )) { fwrite( $file, $_FILES["file"]["name"] . " already exists.\n" ); } else { move_uploaded_file( $_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"] ); fwrite( $file, "Stored in: " . "upload/" . $_FILES["file"]["name"] . "\n" ); } } fclose( $file ); ?> ... which produces the following: 01/08/2012 20:45:11,98.200.58.130 Upload: Type: Size: 0 Kb Temp file: already exists. So, as you can see, the script is being run, but it appears to not have any information about the file being posted. I believe I have the headers set correctly as well as the INTERNET_BUFFERS structure setup correctly. I'm pretty stumped on what to try next as far as debugging this. It's not like I have return values or anything to work with. It just doesn't work and I'm not really sure why. Anyway, any help would be greatly appreciated. Thanks!


You might want to take a look at libcurl to be honest, it makes this whole thing trivial (+ it gives you nifty extras such as callback functions for upload progress and much more)

From your code one thing that appears to be missing (in the C part) is the field name for the POST (Which should be "file" to match the field name you try to read the file from on the PHP end of things)

Share this post


Link to post
Share on other sites
Your PHP script seems to want to access a file called "file", but your program appears to be uploading a file called "testfile.wrp".


I'm pretty stumped on what to try next as far as debugging this. It's not like I have return values or anything to work with. It just doesn't work and I'm not really sure why.
[/quote]
When all else fails, log what is actually happening! For example, if you had logging for all the file names in $_FILES, you might see if "testfile.wrp" is in there.

Share this post


Link to post
Share on other sites
I just made it log the size of the $_FILES array. It is zero :(

I thought after finding the list of header fields that I'd finally have this licked (since I was setting the file name wrong), but for whatever reason it's still not working :(

All I've done is change the headers around. Here is that change:


sprintf_s( szHeaders, "User-Agent: <program name>\r\nContent-Type: multipart/form-data\r\nContent-Disposition: form-data; name=%s; filename=%s\r\nContent-Length: %d", "file", "testfile.wrp", REPLAY_GetReplaySize( ));

Share this post


Link to post
Share on other sites
You can test your PHP in isolation by saving the replay to a file, and writing a HTML form to submit the file to the PHP script. Once you have a form that works, examining this data transmission (e.g. using Firebug) will show you what a proper request should look like.

Looking closer at your code, you don't actually seem to be writing a correct multi-part request. You don't have a boundary. The file specific headers and content should be included together in the request body, suitably delimited by the boundary.

Another option is to use the cURL library.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!