Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
standard
Jan 1, 2005
magic

DarkLotus posted:

You could make one fairly easily if you are good with PHP. The problem isn't just serving images, you have to somehow tell the script where the image is stored on the server. What exactly are you trying to accomplish by not hard coding image paths?

I'm competent but just can't be bothered to think through the security implications to be be honest.
The main reason is that I'm going to serve up different images depending on some user settings.

Good coders code, great reuse...and all that.

Adbot
ADBOT LOVES YOU

DarkLotus
Sep 30, 2001

Lithium Hosting
Personal, Reseller & VPS Hosting
30-day no risk Free Trial &
90-days Money Back Guarantee!

standard posted:

I'm competent but just can't be bothered to think through the security implications to be be honest.
The main reason is that I'm going to serve up different images depending on some user settings.

Good coders code, great reuse...and all that.

Most of the code I have was built for a purpose and not just for general image serving so it probably won't help you much.

As for security, if you are trying to secure the images from prying eyes and only want to serve up images that the user is authorized to view that gets tricky but isn't too difficult.

If a directory called images and just want to serve up images/hello.jpg but would prefer <img src="image.php?i=1" /> as opposed to <img src="images/hello.jpg" /> then that is easy.

standard
Jan 1, 2005
magic

DarkLotus posted:

Most of the code I have was built for a purpose and not just for general image serving so it probably won't help you much.

As for security, if you are trying to secure the images from prying eyes and only want to serve up images that the user is authorized to view that gets tricky but isn't too difficult.

If a directory called images and just want to serve up images/hello.jpg but would prefer <img src="image.php?i=1" /> as opposed to <img src="images/hello.jpg" /> then that is easy.

I meant 'don't give users access to my whole filesystem' type security, rather than authorization type security. :)

DarkLotus
Sep 30, 2001

Lithium Hosting
Personal, Reseller & VPS Hosting
30-day no risk Free Trial &
90-days Money Back Guarantee!

standard posted:

I meant 'don't give users access to my whole filesystem' type security, rather than authorization type security. :)
Very simple and secure if you don't trust the user to put valid content in $_GET['img']... Your path is preset and if the img src contains the proper value you can display an image.

Example: <img src="image.php?img=123456" />
php:
<?php
$imagePath =  '/home/user/public_html/images/';
if ($_GET['img'] == '123456') {
    $imagefile "sample";  // this value can be pulled from a database or whatever!
} else {
    $imagefile "blank";
}
$newimage $imagePath.$imagefile.'.png';
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0"false);
header('Content-Type: image/png');
//  header('Content-Disposition: attachment; filename="' . $_GET['img'] . '.png"');  // FORCE DOWNLOAD
header('Content-Disposition: filename="' $_GET['img'] . '.png"');
  
$img LoadPNG($newimage);
  
imagepng($img);
imagedestroy($img);
?>

This will display sample.png but will show in "View Source" as 123456.png

Lithium Hosting - Reliable, Affordable, Feature Packed Web Hosting
The only hosting company to offer 30-day Free Trial on top of a 90-day money back guarantee!

Give Lithium DNS a try, it's free and easy to use!

DarkLotus fucked around with this message at 20:37 on Jul 20, 2009

supster
Sep 26, 2003

I'M TOO FUCKING STUPID
TO READ A SIMPLE GRAPH

DarkLotus posted:

php:
<?
$img = LoadPNG($newimage);
  
imagepng($img);
imagedestroy($img);
?>
?>

Why are you creating an image object? All you need to do is something like this:
php:
<?
$fh = fopen($newimage, 'r');
while(!feof($fh))
    echo fread($fh, 8192);
?>
You are also allowing the user access to directly modify the response header.

DarkLotus
Sep 30, 2001

Lithium Hosting
Personal, Reseller & VPS Hosting
30-day no risk Free Trial &
90-days Money Back Guarantee!

supster posted:

Why are you creating an image object? All you need to do is something like this:
php:
<?
$fh = fopen($newimage, 'r');
while(!feof($fh))
    echo fread($fh, 8192);
?>
They both work... Is there a good reason not to do it that way? I prefer file_get_contents over fread anyways. The problem with an open source language with many ways of doing anything is that there is no true wrong way or right way unless you are creating a huge security hole.

supster posted:

You are also allowing the user access to directly modify the response header.
Not if you clean the $_GET value. Protect it like you would a SQL Query.

DarkLotus fucked around with this message at 23:38 on Jul 20, 2009

gibbed
Apr 10, 2006

supster posted:

php:
<?
$fh = fopen($newimage, 'r');
while(!feof($fh))
    echo fread($fh, 8192);
?>
No.

readfile

Edit: ignore this stupid advice

gibbed fucked around with this message at 00:38 on Jul 21, 2009

supster
Sep 26, 2003

I'M TOO FUCKING STUPID
TO READ A SIMPLE GRAPH

DarkLotus posted:

They both work... Is there a good reason not to do it that way? I prefer file_get_contents over fread anyways. The problem with an open source language with many ways of doing anything is that there is no true wrong way or right way unless you are creating a huge security hole.
Your original way and get_file_contents both need to load the entire file into memory before outputting it - if you were serving a 500MB file that's 500MB used for the entire duration of the request's life. readfile is avoided for the same reason. Additionally I'm pretty sure there's significant overhead with creating an image object and using imagepng.


edit: I actually left out some things in my original code that I was reminded by when I was looking at the readfile docs to make sure I wasn't crazy. Here's the full proper way of doing this (as far as I am concerned, at least):
php:
<?
$fh = fopen($newimage, 'rb');
while(!feof($fh))
{
    echo fread($fh, 8192);
    ob_flush();
    flush();
}
?>

supster fucked around with this message at 00:41 on Jul 21, 2009

gibbed
Apr 10, 2006

supster posted:

readfile is avoided for the same reason
readfile doesn't read and output in chunks? That's horrible.

supster
Sep 26, 2003

I'M TOO FUCKING STUPID
TO READ A SIMPLE GRAPH

gibbed posted:

readfile doesn't read and output in chunks? That's horrible.
php :smug:

gibbed
Apr 10, 2006

Just read the code. Internally readfile() opens a handle to the file then uses passthru on the handle. The passthru code attempts to mmap the file and writes it out in that case, otherwise it reads the file in 8192 byte chunks and writes them out. So, I'm assuming the problem here is buffering rather than readfile itself, because readfile itself is fine.

supster
Sep 26, 2003

I'M TOO FUCKING STUPID
TO READ A SIMPLE GRAPH
Yeah, that is correct. The problem isn't in reading the file (which passthru does fine at 8KB chunks), but rather writing. The file gets written to PHP's internal output buffer, which generally doesn't get flushed until the end of the script's execution. The explicit call to ob_flush() forces that output to be sent to the web server (or whatever PHP is running off of) after every chunk.

edit: look at php_end_ob_buffer() in output.c if you want to see what's going on, it's pretty dumb.

supster fucked around with this message at 01:10 on Jul 21, 2009

DarkLotus
Sep 30, 2001

Lithium Hosting
Personal, Reseller & VPS Hosting
30-day no risk Free Trial &
90-days Money Back Guarantee!
Lets assume that we are in control of the size of files we are serving up with an image script. If that is true, is it still an issue or has it turned into a best practice scenario now?

gibbed
Apr 10, 2006

It's ideal to not use up more resources than you have to, even if the amount of resources are insignificant.

waffle iron
Jan 16, 2004
If you're going to serve up random images or other poo poo like that, never ever output it in a PHP file unless they're really loving tiny. Because you're not sending Cache headers the browser redownloads it every time.

You're better off writing to a folder if the image is dynamic and then sending a 302 or 307 HTTP status with a Location header.

I repeat: using PHP to send binary data is extra retarded. That goes double for serving images out of a database with PHP.

waffle iron fucked around with this message at 02:26 on Jul 21, 2009

DarkLotus
Sep 30, 2001

Lithium Hosting
Personal, Reseller & VPS Hosting
30-day no risk Free Trial &
90-days Money Back Guarantee!

waffle iron posted:

That goes double for serving images out of a database with PHP.

Yeah, storing images in a db is retarded.

waffle iron
Jan 16, 2004

DarkLotus posted:

Yeah, storing images in a db is retarded.
The only way it might be useful is if you write out images too static web server on the first request, store that filename in a table and serve it out as a Location header.

The moral of the story is static content or content that changes less than once a day should be served off a static web server or cached to disk and served from a static web server.

supster
Sep 26, 2003

I'M TOO FUCKING STUPID
TO READ A SIMPLE GRAPH

waffle iron posted:

I repeat: using PHP to send binary data is extra retarded. That goes double for serving images out of a database with PHP.
This is way too wide of a generalization. There are a lot of legitimate reasons for doing it. Additionally, just because you're serving the file through PHP doesn't mean you can't set cache-control or expires headers - in fact it gives you more control to make better use of them.

MrMoo
Sep 14, 2000

standard posted:

Does anyone know of a nice image serving type script?

For public or private use? I wrote one after a request sometime before, I recently updated it for some speed tweaking after Google published their performance article:

http://junko.hk/junko-php-latest.tbz2

Supports i18n, Gears, loading from URL, thumbnails, etc.

waffle iron
Jan 16, 2004

supster posted:

This is way too wide of a generalization. There are a lot of legitimate reasons for doing it. Additionally, just because you're serving the file through PHP doesn't mean you can't set cache-control or expires headers - in fact it gives you more control to make better use of them.
Oh man you're hilarious. You think people actually send e-tags or expires headers when they're coming to the internet for help.

Yossarko
Jan 22, 2004

I'm looking for a PHP function that will compare a date with today's date and then return humanized strings such as "today", "yesterday", "in 2 days" "in 3 months", "3 years ago".

Similar to "Posted" timestamp on these forums (posted 4 hours ago). I could probably manage to do it myself but it seems like a lot of hassle for something that probably exists as a function.

I've tried searching...probably aren't typing the right keywords.

Alex007
Jul 8, 2004

Yossarko posted:

I'm looking for a PHP function that will compare a date with today's date and then return humanized strings such as "today", "yesterday", "in 2 days" "in 3 months", "3 years ago".

This is the function I use, I don't remember where I took it from unfortunately.

code:

function timeDiff($timestamp,$now,$detailed=false, $max_detail_levels=8, $precision_level='second'){
    #If the difference is positive "ago" - negative "away"
    $action = ($timestamp > $now)?'away':'ago';
  
    # Set the periods of time
    $periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade");
    $lengths = array(1, 60, 3600, 86400, 604800, 2630880, 31570560, 315705600);

    $diff = abs($now - $timestamp);
  
    $prec_key = array_search($precision_level,$periods);
  
    # round diff to the precision_level
    $diff = round(($diff/$lengths[$prec_key]))*$lengths[$prec_key];
 
 
    # if the diff is very small, display for ex "just seconds ago"
    if ($diff <= 1) {
        $periodago = max(0,$prec_key-1);
        $agotxt = $periods[$periodago].'s';
        return "just $agotxt $action";
    }
  
    # Go from decades backwards to seconds
    $time = "";
    for ($i = (sizeof($lengths) - 1); $i>0; $i--) {
        if($diff > $lengths[$i-1] && ($max_detail_levels > 0)) {        # if the difference is greater than the length we are checking... continue
            $val = floor($diff / $lengths[$i-1]);    # 65 / 60 = 1.  That means one minute.  130 / 60 = 2. Two minutes.. etc
            $time .= $val ." ". $periods[$i-1].($val > 1 ? 's ' : ' ');  # The value, then the name associated, then add 's' if plural
            $diff -= ($val * $lengths[$i-1]);    # subtract the values we just used from the overall diff so we can find the rest of the information
            if(!$detailed) { $i = 0; }    # if detailed is turn off (default) only show the first set found, else show all information
            $max_detail_levels--;
        }
    }
 
    # Basic error checking.
    if($time == "") {
        return "(Error-- Unable to calculate time diff)";
    } else {
        return $time.$action;
    }
}
And this is how I call it:

code:
echo timeDiff($Event['TimeStamp'], $this->dateutils->gmtime(), true, 2);

Yossarko
Jan 22, 2004

Thank you, it's perfect.

Safety Shaun
Oct 20, 2004
the INTERNET!!!1
I'm messing around with the Google Maps API and Google's Latitude and wondered how I would construct a regex to return only "latitude_e6=[NUMBERS-INCLUDING-MINUS-SIGN]&longitude_e6=[NUMBERS-INCLUDING-MINUS-SIGN]" from the fopen() results. Possibly even throw those values into their own variables.

Thank you in advance

spiritual bypass
Feb 19, 2008

Grimey Drawer

Safety Shaun posted:

I'm messing around with the Google Maps API and Google's Latitude and wondered how I would construct a regex to return only "latitude_e6=[NUMBERS-INCLUDING-MINUS-SIGN]&longitude_e6=[NUMBERS-INCLUDING-MINUS-SIGN]" from the fopen() results. Possibly even throw those values into their own variables.

Thank you in advance

http://www.php.net/manual/en/function.parse-url.php

Safety Shaun
Oct 20, 2004
the INTERNET!!!1
Sorry for not explaining myself correctly. The GPS location is in the source of the body I am retriving, not the URL.

spiritual bypass
Feb 19, 2008

Grimey Drawer
What does the file look like?

Safety Shaun
Oct 20, 2004
the INTERNET!!!1

royallthefourth posted:

What does the file look like?
php:
<?
        $handle = fopen("http://www.google.com/latitude/apps/badge/api?user=99999999999999&type=iframe&maptype=hybrid&z=20", "rt");
        $contents = '';
        while (!feof($handle)) {
          $contents .= fread($handle, 8192);
        }
        fclose($handle);
?>
The source returned in $contents is a mixture of HTML and Javsascipt but the substring I want only exists once in the whole string.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Safety Shaun posted:

Sorry for not explaining myself correctly. The GPS location is in the source of the body I am retriving, not the URL.

Use preg_match with /latitude_e6=(-?\d+\.\d+)/ and /longitude_e6=(-?\d+\.\d+)/ and $matches[1] should contain your number. If they ever use floats without leading zeroes, the first \d would have to be followed by a * instead of a +.

Aaand I guess you could use /(latitude|longitude)_e6=(-?\d+\.\d+)/ and deal with the more complex return array. Whichever.

Safety Shaun
Oct 20, 2004
the INTERNET!!!1

Munkeymon posted:

Use preg_match

Thanks but I'm having trouble getting it to work.

Here is a snippet of the returned string with the actual GPS location changed slighly.

code:
setTop(e('belowPromo')) - calculateOffsetTop(e('abovePromo')));
var mapWidth = getWindowWidth() - (16);
e('map').src = "http://www.google.com/mapdata?latitude_e6=51741341&longitude_e6=-231444&w=0&h=0&hl=en&zl=-3&cc=us&tstyp=3".replace(/&w=\d+/, "&w=" + mapWidth).replace(/&h=\d+/, "&h=" + mapHeight);
e('map').width = mapWidth;
e('map').height = mapHeight;

supster
Sep 26, 2003

I'M TOO FUCKING STUPID
TO READ A SIMPLE GRAPH

waffle iron posted:

Oh man you're hilarious. You think people actually send e-tags or expires headers when they're coming to the internet for help.
Oh man you're hilarious. You think it actually matters whether people serve their files statically or through PHP when they're coming to the internet for help.


All I'm saying is that you're absolutely wrong when saying "never ever output it in a PHP file" - it can be the correct solution and you're not creating any sort of caching problems if you do it right.


In reality I just finished working on a 6-month project I designed that involved serving files through PHP and felt the need to defend it :mad:

supster fucked around with this message at 20:55 on Jul 21, 2009

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Safety Shaun posted:

Thanks but I'm having trouble getting it to work.

Here is a snippet of the returned string with the actual GPS location changed slighly.

Oh, sorry, I just assumed they would be floats for some reason. Take out the \.\d+ part: /(latitude|longitude)_e6=(-?\d+)/

Edit: or, if you think they will ever be floats and want to be safe /(latitude|longitude)_e6=(-?\d+(?:\.\d+)?)/

Munkeymon fucked around with this message at 21:33 on Jul 21, 2009

Safety Shaun
Oct 20, 2004
the INTERNET!!!1

Munkeymon posted:

Oh, sorry, I just assumed they would be floats for some reason.

Thanks so far, sir.

[php] $pattern = "/latitude_e6=(-?\d+(?:\.\d+)?)/";
preg_match($pattern, $contents, $matches);
//print_r($matches);
$lat = $matches[1];
[php]
This prints out the value as an integer, is there anything I am wrong?

Agrikk
Oct 17, 2003

Take care with that! We have not fully ascertained its function, and the ticking is accelerating.
How do I insert items randomly into an array of fixed size and avoid collisions?

I have a list of items that I need to insert randomly into an array. The number of items will always be smaller than the size of the array and in the event of a collision I need to pick another random spot in the array.



How can I do this?

supster
Sep 26, 2003

I'M TOO FUCKING STUPID
TO READ A SIMPLE GRAPH

Agrikk posted:

How do I insert items randomly into an array of fixed size and avoid collisions?

I have a list of items that I need to insert randomly into an array. The number of items will always be smaller than the size of the array and in the event of a collision I need to pick another random spot in the array.



How can I do this?
I can almost gaurantee there's a better way to do what you're trying to accomplish. What are you trying to accomplish? shuffle may be what you're looking for.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Safety Shaun posted:

Thanks so far, sir.

php:
<?
        $pattern = "/latitude_e6=(-?\d+(?:\.\d+)?)/";
        preg_match($pattern, $contents, $matches);
        //print_r($matches);
        $lat = $matches[1];
?>
This prints out the value as an integer, is there anything I am wrong?

No, the extra junk just keeps it from missing out on the decimals in floats if they ever get sent. If you make your own test data with decimal places you should see the difference.

Safety Shaun
Oct 20, 2004
the INTERNET!!!1

Munkeymon posted:

If you make your own test data with decimal places you should see the difference.
My output is this:
code:
Array ( [0] => latitude_e6=13744341 [1] => 13744341 ) Array ( [0] => longitude_e6=-132443 [1] => -132443 ) 
Co-ordinates are lat,long 13744341,-132443

Safety Shaun fucked around with this message at 22:36 on Jul 21, 2009

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Safety Shaun posted:

My output is this:
code:
Array ( [0] => latitude_e6=13744341 [1] => 13744341 ) Array ( [0] => longitude_e6=-132443 [1] => -132443 ) 
Co-ordinates are lat,long 13744341,-132443

I get the whole thing:
php:
<?
preg_match('/latitude_e6=(-?\d+(?:\.\d+)?)/',
           'somewhereAtGoogle?latitude_e6=-51741341.123&longitude_e6=-231444&w=0&h=0&hl=en&zl=-3&cc=us&tstyp=3',
           $matches);
print_r($matches);
?>
code:
    [0] => latitude_e6=-51741341.123
    [1] => -51741341.123
so I dunno.

spiritual bypass
Feb 19, 2008

Grimey Drawer
I'm pretty sure parse_url will do this without any need for regexes. It doesn't actually need to be a URL, it'll take anything formatted key1=value1&key2=value2

Adbot
ADBOT LOVES YOU

Agrikk
Oct 17, 2003

Take care with that! We have not fully ascertained its function, and the ticking is accelerating.

supster posted:

I can almost gaurantee there's a better way to do what you're trying to accomplish. What are you trying to accomplish? shuffle may be what you're looking for.

To pull out the :nerd: hat here, I am writing a script that generates a star system around existing data based on the rules set forth in the MegaTraveller RPG.

I have a database of approximately 50,000 star systems and each system has 1-4 suns, 0-7 gas giants, 0-3 asteroid belts and assorted worlds.

The game's star system generation chapter has a pretty detailed method for generating orbital bodies in a star system and I am automating it using php/mysql.

My current thought is to have an array that represents the orbits of the system and all of the sub orbits (for moons around worlds, binary & trinary systems, etc).

The rules have a complicated method to place suns in a system randomly but with many modifiers, then to place gas giants, then belts, then worlds each with its own set of rules and modifiers. Since an orbit can only contain one object, rerolls are necessary.

Here's the core of what I have so far, but it's broken. It doesn't check if the array is occupied properly, so if the array item is occupied, it gets overwritten buy the incoming record:

code:
<?php

$CompanionOrbitChart = array(0,0,1,2,3,4+rand(1,6),5+rand(1,6),6+rand(1,6),7+rand(1,6),8+rand(1,6),15);


	unset($SystemArray);
	$starcount = rand(1,4);

	//load first star into Array
	$SystemArray[0][0][0] = "Star1";

	//load the rest of the stars
	
	$StarNumber=2;
	while ($StarNumber <= $starcount) 
	{
		do
		{
			$random = (rand(1,6)+(rand(1,6)))-2;
			if ($random > 10) $random = 10;
			$LocationRoll[$StarNumber] = $random;
			
			$CompanionOrbit = $CompanionOrbitChart[$random];
			while (empty($SystemArray[$CompanionOrbit][0][0])) 
			{
				$SystemArray[$CompanionOrbit][0][0] = "Star$StarNumber";
				break 2;
			}
		} while (0);
		$StarNumber++;
	}

	print_r($SystemArray);
?>

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply