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
v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.

stoops posted:

If I have this working correctly, should i still rename the file uploaded?

As revmoo said, yes, rename the file to avoid collisions. If you're paranoid (like me!) you can do something like this:
code:
do {
    $hash = sha1(uniqid(mt_rand(), true));
    $available = file_exists($hash);
} while (!$available)
That'll just loop until it generates a filename that isn't already taken.
Use the database to keep a record of the original filename, the new hash path, etc..

As the file isn't at a browsable location, you don't really have a risk of it being a server-executable script anymore, so that's nice. But you do need to serve it back to the user with the original filename, so you can do something like:
code:
        // Open the file
        $fileHandle = new \SplFileInfo($path)->openFile('r');

        // File headers to force download
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.$fileName.'"');
        header('Content-Length: '. $fileHandle->getSize());
        header("Content-Transfer-Encoding: binary");

        // Cache headers (no cache)
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');

        // Connection header (early hangup when finished)
        header("Connection: close");

        // Read file from start to end and shove at the browser.
        $fileHandle->fpassthru();
The use of fpassthu is important because it'll feed data directly through from the file to the output buffer. Unlike using straight fread() it won't clog up PHPs memory limit, so you don't need to worry about chunking, output buffering, etc. This means you can passthu huge files (gagabytes!) with a much lower PHP memory limit.

Adbot
ADBOT LOVES YOU

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.

poxin posted:

I have an array that I am pulling from a (crap)API

I'm trying to pull out specific values from that array and loop them into a grid

I've tried printing single values from the array itself such as "server_name" but I can't get that even working - just a blank page no matter what I try.

It sounds like you've got bigger problems if you can't even echo stuff out. Are you sure you don't have a syntax or other error and you've just got errors suppressed?
Try this after your API call:
code:
ini_set('display_errors', true);
error_reporting(E_ALL);
trigger_error("This is why we can't have nice things");
If you don't see the error, then something's fucky. If you do, remove trigger_error and then try the rest of your code.

As the for rest of your problem, here's the quickest brute-force method I could think of;
code:
// Call API to get servers
$rawData = $admin->servers();

// Data mapping
$map = [
    'server_name' => 'Node',
    'space' => 'Disk_Free',
    'total_space' => 'Total_Disk',
];

// Remap data
$data = [];
foreach ($rawData['servs'] as $row) {
    $item = [];
    foreach ($map as $from => $to) {
        $item[$to] = $row[$from];
    }
    $data[] = $item;
}

// encode JSON
$json = json_encode($data);

// Done and done
echo $json;

poxin
Nov 16, 2003

Why yes... I am full of stars!

v1nce posted:

If you don't see the error, then something's fucky. If you do, remove trigger_error and then try the rest of your code.

print_r($output); worked just fine using the API to produce the array. I was having problems trying to get any data out of it and format it the way I need.

I think I see what your code is doing, thank you very much for that! It's looking pretty close to what I'm attempting to do with it.

Edit: Quick question, what would be the correct syntax for doing an operation under $map

code:
'space' => 'Disk_Free',
'total_space' => 'Total_Disk',
'space/total_space' => 'Disk_Free_Precent',

poxin fucked around with this message at 00:58 on Dec 4, 2015

substitute
Aug 30, 2003

you for my mum

v1nce posted:

As the file isn't at a browsable location, you don't really have a risk of it being a server-executable script anymore, so that's nice. But you do need to serve it back to the user with the original filename, so you can do something like:
code:
        // Open the file
        $fileHandle = new \SplFileInfo($path)->openFile('r');

        // File headers to force download
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.$fileName.'"');
        header('Content-Length: '. $fileHandle->getSize());
        header("Content-Transfer-Encoding: binary");

        // Cache headers (no cache)
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');

        // Connection header (early hangup when finished)
        header("Connection: close");

        // Read file from start to end and shove at the browser.
        $fileHandle->fpassthru();
The use of fpassthu is important because it'll feed data directly through from the file to the output buffer. Unlike using straight fread() it won't clog up PHPs memory limit, so you don't need to worry about chunking, output buffering, etc. This means you can passthu huge files (gagabytes!) with a much lower PHP memory limit.

And could also use Cake's Response object to serve up file downloads.

http://book.cakephp.org/2.0/en/controllers/request-response.html#sending-files

I've used this concept to create a download controller method along with routing to serve non-public files as pretty URLs in <a href> links.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
You want to run a function to modify the format of the data? that's a bit more complicated.
The map is just saying A=>B or A becomes B. The foreach does the legwork.

Here's a more exciting example of a mapper that uses anonymous functions to process each row of data.
code:
// Data mapping
$map = [
    'server_name' => [
        'key' => 'Node',
    ],
    'space' => [
        'key' => 'Disk_Free',
        'normalize' => function ($data) {
            return number_format($data / 1000, 3);
        },
    ],
    'total_space' => [
        'key' => 'Total_Disk',
    ],
];

// Remap data
$data = [];
foreach ($rawData['servs'] as $row) {
    $item = [];
    foreach ($map as $fieldName => $field) {

        // Validate key exists
        if (!isset($field['key'])) {
            throw new LogicException(sprintf('Field %s must supply a key', $fieldName));
        }

        // Get data from API
        if (isset($row[$fieldName])) {
            $value = $row[$fieldName];
        } else {
            // Use null if data not given by API
            $value = null;
        }


        // Run normalize where set
        if (isset($field['normalize']) && is_callable($field['normalize'])) {
            $value = call_user_func($field['normalize'], $value);
        }

        // Map to new data
        $item[$field['key']] = $value;
    }
    $data[] = $item;
}
You don't really want to go beyond that in procedural code. If it needs to be more advanced then you should introduce some OOP into your life.

poxin
Nov 16, 2003

Why yes... I am full of stars!

v1nce posted:

You don't really want to go beyond that in procedural code. If it needs to be more advanced then you should introduce some OOP into your life.

You are my hero, actually learning a hell of lot from this. While being able to format the data is awesome I was looking to do something under data mapping where I have "space" and "total_space" in an attempt to divide those two in order to get a percentage value.

code:
Disk_Free:              space
Total_Disk:             total_space
Disk_Free_Percent:      calculatedfield (space/total_space)
Free_RAM:               ram
Total_RAM:              total_ram
Free_RAM_Percent:       calculatedfield (ram/total_ram)

MrMoo
Sep 14, 2000

I have an obvious question, if Facebook are so smart and the PHP developers so dumb how is PHP 7 significantly faster than HHVM?

Am I answering my owner question in that they are gaming the benchmarks by using new features that are only in PHP 7?

McGlockenshire
Dec 16, 2005

GOLLOCKS!
PHP 7 is only faster than HHVM for certain operations.

Overall, PHP 7 is still slightly slower than HHVM in most non-artificial benchmarks, but there's no longer a huge performance gulf between the two.

Also, it's only a few members of internals that are dumb. Check out the last few entrys on NikiC's blog: https://nikic.github.io/

poxin
Nov 16, 2003

Why yes... I am full of stars!

poxin posted:

You are my hero, actually learning a hell of lot from this. While being able to format the data is awesome I was looking to do something under data mapping where I have "space" and "total_space" in an attempt to divide those two in order to get a percentage value.

Think I figured this out
code:
'disk_percent' => [
     'key' => 'Disk_Free_Percent',
      	'normalize' => function ($field, $data) {
	       	if ($data['total_space'] > 0) {
	           return $data['space'] / $data['total_space'];
	       	}
          return 0;
       },
],
Now to figure out how to format the numbers on it :)

stoops
Jun 11, 2001
I have this array

code:
array(
	(int) 2015 => array(
		'08' => array(
			(int) 0 => '20150828 - MMS MP Crossing - shear.gif',
			(int) 1 => '20150828 - MMS MP Crossing - sw.gif'
		),
		'09' => array(
			(int) 0 => '20150902 - MMS MP Crossing - shear.gif',
			(int) 1 => '20150902 - MMS MP Crossing - sw.gif',
			(int) 2 => '20150903 - MMS MP Crossing - shear.gif',
			(int) 3 => '20150903 - MMS MP Crossing - sw.gif'
		),
		(int) 10 => array(
			(int) 0 => '20151016 - MMS MP Crossing - sw - Copy [2].gif'
		),
		(int) 11 => array(
			(int) 0 => '20151116 - MMS MP Crossing - sw - Copy.gif'
		)
	)
)
Whats bothering me are that the months, 10 and 11, are integers whereas the 08 and 09 are not. I'm using this array for a tree structure and the order is messed up. its showing me 10, 11, 08, 09 on my view.

I've tried to convert the month to string but it still shows it as an integer.

Any help is appreciated.

revmoo
May 25, 2006

#basta
How did you try converting to string?

I would cast. Ie:

$month = '11';
echo (string) $month;

stoops
Jun 11, 2001

revmoo posted:

How did you try converting to string?

I would cast. Ie:

$month = '11';
echo (string) $month;

That's exactly how I did it and it still showed up exactly as the array I posted.

I ended up concatenating a blank space so it can automatically convert it to a string, but I feel what you posted should have worked.

karms
Jan 22, 2006

by Nyc_Tattoo
Yam Slacker
Probably has something to do with that the other two months are casted to strings to preserve the leading zero. Start your search with the part of code that does that.

McGlockenshire
Dec 16, 2005

GOLLOCKS!
Dollars to donuts it's happening because of implicit octal conversion. What happens when there's, say, '01' through '07'? That'd then break on '08' and '09', which aren't valid when converting octal to integer. 10 and 11 bypass it, no leading zero.

Pile Of Garbage
May 28, 2007



McGlockenshire posted:

implicit octal conversion

:allears:

stoops
Jun 11, 2001
I have an intranet server with many folders. Each folder is its own site. Each site folder has its own instance of cakephp installed. Some sites have an older version of cake, others have a new version.

To get to any site it would be something like:

http://myserver.com/site1
http://myserver.com/site2
http://myserver.com/site3

and so on....

Each site has its own login/database and they all work fine.

My problem comes with the browser, saving passwords.

When I try to save my password for a particular site, it saves it as: http://myserver.com/

I'm not sure what to do, either on cakephp or on the folder (maybe htaccess?), to make it known that the folder is a website and should be saved as http://myserver.com/site3 or whatever.

Hope what I wrote makes sense. Any help is appreciated. I would google this, but I'm not entirely sure the search terms.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
You're looking for cookie path.
If you set a cookies path to "/" it's available across the entire domain. If you set it to "/derp/" then it's only available to pages under derp, such as "/derp/herp".

You can set this globally (i think) in Cake3 and Cake2.

stoops
Jun 11, 2001

v1nce posted:

You're looking for cookie path.
If you set a cookies path to "/" it's available across the entire domain. If you set it to "/derp/" then it's only available to pages under derp, such as "/derp/herp".

You can set this globally (i think) in Cake3 and Cake2.

Thanks, but I may have constructed my question wrong.

To me, a cookie means to save a user from having to log in again. (they are just automatically logged in)

What I'm trying to do is let the browser use its "autocomplete form". Usually when I go to any website with a login, I click on the textbox and usernames pop up for that site, then when I click on one of them, the password pops in the password field and then I can click submit to login.

The problem I'm having is that all the site folders I have, for some reason, aren't saved to the Browser as http://myserver.com/site2. only as http://myserver.com/

In my case, I use the same username for every site, but I use different passwords for each site.

So when i go to site3, and i click for the autocomplete, it will give me the password for whatever last site i logged in instead of the password for this specific site.

Maybe this is not a php question? Basically, all the folders on my server are websites, but the browser autocomplete thinks its all one domain.

Begby
Apr 7, 2005

Light saber? Check. Black boots? Check. Codpiece? Check. He's more machine than kid now.

stoops posted:

Thanks, but I may have constructed my question wrong.

To me, a cookie means to save a user from having to log in again. (they are just automatically logged in)

What I'm trying to do is let the browser use its "autocomplete form". Usually when I go to any website with a login, I click on the textbox and usernames pop up for that site, then when I click on one of them, the password pops in the password field and then I can click submit to login.

The problem I'm having is that all the site folders I have, for some reason, aren't saved to the Browser as http://myserver.com/site2. only as http://myserver.com/

In my case, I use the same username for every site, but I use different passwords for each site.

So when i go to site3, and i click for the autocomplete, it will give me the password for whatever last site i logged in instead of the password for this specific site.

Maybe this is not a php question? Basically, all the folders on my server are websites, but the browser autocomplete thinks its all one domain.

Yeah, this is a problem with your browser just saving the login for the entire domain. You can try a third party tool such as 1password. I have had better luck doing it that way.

Our company intranet lets us edit clients and has a field labeled 'email address', so for awhile every time I edited a client the browser would just go ahead and auto fill that email address with my personal email address and I didn't notice. Then for several days I was getting all these client notifications and clients started bitching to customer service that our system was all broken and poo poo.

So yeah... there ya go, autocomplete is cool in some ways, but other times it sucks.


Long term though, aside from the subfolder password issues, its often beneficial to setup a separate domain for each site. So you would have site1.myserver.com, site2.myserver.com etc. This becomes a huge deal if it ever comes time to say migrate a specific site to a new version of php on a new server, or if you need to split up sites on different servers due to server load. You can also do poo poo at the router with the domain if you need to. This will resolve any issues with cookies, and as a side benefit this would also fix the issue you are having with the passwords. Its good practice to do that with the database server as well, instead of using localhost or https://www.myserver.com use db1.myserver.com or some poo poo.

hedgecore
May 2, 2004
Is there a modern, free solution to convert some HTML/CSS to a PDF through PHP?

I found a SO answer but the top answer is from 2009. It's not my place in this organization to propose installing node.js/phantom to do it (which is the only way I've handled this problem so far).

musclecoder
Oct 23, 2006

I'm all about meeting girls. I'm all about meeting guys.

hedgecore posted:

Is there a modern, free solution to convert some HTML/CSS to a PDF through PHP?

I found a SO answer but the top answer is from 2009. It's not my place in this organization to propose installing node.js/phantom to do it (which is the only way I've handled this problem so far).

There's a few libraries https://packagist.org/packages/dompdf/dompdf that are common. However, if this is for a company tell them to stop being such cheap asses and use DocRaptor - https://docraptor.com/

Tiny Bug Child
Sep 11, 2004

Avoid Symmetry, Allow Complexity, Introduce Terror
Laravel is about to make me lose my poo poo. I've got these two Eloquent models, Thing and ThingBag. Thing has a BelongsTo relationship with ThingBag, and ThingBag has a HasMany relationship with Thing.

So I iterate over the Things in the ThingBag and do some work with them. I may need to remove a Thing from the ThingBag, which I do with:

code:
    $thing->myBag()->dissociate();
    $thing->push();
The problem is that doesn't update the ThingBag's Collection of Things--after the work is done, the page dumps out a list of the ThingBag's contents and the Thing will still be listed, even though they're no longer associated in the database. Okay, maybe I just need to update the ThingBag's too. But HasMany doesn't have a dissociate(), or any equivalent to it, as far as I can tell. I can do this:

code:
$thingbag->things = $thingbag->things->filter(function($v) use ($thething) {
    return $v->thing_id != $thething->thing_id;
});                                                                                                   
Which is hideous, but it does exactly what I want. Except the problem there is that Laravel thinks I'm trying to set a "things" property, not just set the relation defined by the "things()" method. So if I try to save the ThingBag after this, it tries to write a serialized string to the non-existent "things" column and barfs. HasMany::saveMany() appears to merge the Collection you give it with what the model already has, rather than replacing it, so if I filter the Collection and give it to saveMany() nothing actually happens.

This has got to be a common enough problem that I've just overlooked something in Laravel's vast, comprehensive documentation, right?

substitute
Aug 30, 2003

you for my mum

hedgecore posted:

Is there a modern, free solution to convert some HTML/CSS to a PDF through PHP?

I found a SO answer but the top answer is from 2009. It's not my place in this organization to propose installing node.js/phantom to do it (which is the only way I've handled this problem so far).

Try mPDF.

https://github.com/mpdf/mpdf

revmoo
May 25, 2006

#basta
Wkhtmltopdf is rad. Also there's a composer plg

Depressing Box
Jun 27, 2010

Half-price sideshow.

Tiny Bug Child posted:

Laravel is about to make me lose my poo poo. I've got these two Eloquent models, Thing and ThingBag. Thing has a BelongsTo relationship with ThingBag, and ThingBag has a HasMany relationship with Thing.

So I iterate over the Things in the ThingBag and do some work with them. I may need to remove a Thing from the ThingBag, which I do with:

code:
    $thing->myBag()->dissociate();
    $thing->push();
The problem is that doesn't update the ThingBag's Collection of Things--after the work is done, the page dumps out a list of the ThingBag's contents and the Thing will still be listed, even though they're no longer associated in the database. Okay, maybe I just need to update the ThingBag's too. But HasMany doesn't have a dissociate(), or any equivalent to it, as far as I can tell. I can do this:

code:
$thingbag->things = $thingbag->things->filter(function($v) use ($thething) {
    return $v->thing_id != $thething->thing_id;
});                                                                                                   
Which is hideous, but it does exactly what I want. Except the problem there is that Laravel thinks I'm trying to set a "things" property, not just set the relation defined by the "things()" method. So if I try to save the ThingBag after this, it tries to write a serialized string to the non-existent "things" column and barfs. HasMany::saveMany() appears to merge the Collection you give it with what the model already has, rather than replacing it, so if I filter the Collection and give it to saveMany() nothing actually happens.

This has got to be a common enough problem that I've just overlooked something in Laravel's vast, comprehensive documentation, right?

You can call $thingbag->load('things') to refresh the model's things relationship from the database.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.

revmoo posted:

Wkhtmltopdf is rad. Also there's a composer plg
If you're only working with HTML, wkhtmltopdf it is indeed rad.

If you're working with JavaScript, you can use PhantomJS to headlessly generate a PDF from a page, which seems to be the "modern" way to handle the problem.

Tiny Bug Child
Sep 11, 2004

Avoid Symmetry, Allow Complexity, Introduce Terror

Depressing Box posted:

You can call $thingbag->load('things') to refresh the model's things relationship from the database.

Yeah, but I'd prefer not to hit the database again for something I already know.

Depressing Box
Jun 27, 2010

Half-price sideshow.

Tiny Bug Child posted:

Yeah, but I'd prefer not to hit the database again for something I already know.

Ok, then instead of assigning directly to $thingbag->things, try:

PHP code:
$thingbag->setRelation('things', $filteredThings);

Tiny Bug Child
Sep 11, 2004

Avoid Symmetry, Allow Complexity, Introduce Terror

Depressing Box posted:

Ok, then instead of assigning directly to $thingbag->things, try:

PHP code:
$thingbag->setRelation('things', $filteredThings);

That's exactly what I needed, thanks a lot.

hedgecore
May 2, 2004
Thanks for the recommendations. I'll try those out. It's a fairly simple layout so hopefully that will play to my advantage.

stoops
Jun 11, 2001
I have alot of images inaccessible from the outside (I put them outside of webroot). But once you log in and are authenticated, I use cakephp's response method for the pictures to show up.

This works fine for a little amount of pictures, but now, as I'm hitting about 120 pics a page, a lot of the images aren't coming out (some images come out sporadically).

I have a feeling it's my image request, that i'm doing wrong.

in the view
code:
<?php echo $this->Html->image ('/plots/get_file/view/'.$basename.'.gif',array('width'=>'200', 'height'=>'155'));?>
in my controller
code:
function get_file ($action, $filename)
    {
        if ($action == 'view') {
			$this->response->file(Configure::read ('shearPlotsMovies').'singleframe/'.$filename);
} 
		return $this->response;
    }

On firefox console, when an image correctly shows up, i get:

GET http://domain/plots/get_file/view/image1.gif [HTTP/1.1 302 Found 3718ms]
GET http://domain/plots/get_file/view/image2.gif [HTTP/1.1 302 Found 3754ms]

but when an image doesnt show up, I get

GET http://domain/ [HTTP/1.1 200 OK 856ms]


Is it that i'm doing it wrong in Cake, or that the browser can't handle showing that many images?

Each image is about 8k, 792*612 but i default the width and height to 200*155

Any help is appreciated.


I can't really divulge the link, but if anyone wants to look at it to see what I mean, I can PM you.

Forgall
Oct 16, 2012

by Azathoth
I'm not familiar with cakephp, but if you are sending 120 simultaneous requests that need to be processed by your php framework some of them probably fail because your server is running out of resources. I think simplest, though maybe not the most correct thing would be to include images into the page itself in base64 encoding in the form of
code:
<img src="data:image/gif;base64,base64-encoded content of image file goes here" />
Also you could put images into amazon s3 bucket, and generate pre-signed urls using amazon sdk to access them.

Forgall fucked around with this message at 22:35 on Jan 15, 2016

poxin
Nov 16, 2003

Why yes... I am full of stars!
What do you folks like for a http client library? I have some scripts written using curl and attempted to move them over to Guzzle. It almost seems easier for to just use curl for simple API tasks. I found Httpful which is actually quite nice and will probably use that instead unless there are better suggestions.

Impotence
Nov 8, 2010
Lipstick Apathy
composer require rmccue/requests

duck monster
Dec 15, 2004

LET IT BE KNOWN that Symfony can go and eat a bag of dicks. Never let java programmers near your framework people, things can only go wrong.

:negative:

McGlockenshire
Dec 16, 2005

GOLLOCKS!
All well designed frameworks end up looking like that. Once you realize what stupid architecture you need in order to get a reasonable design that is also testable, ending up with AbstractGenericRepositoryFactoryImplementations is a given.

I've ended up using a bunch of smaller libraries instead of going full framework. It sometimes ends up being more work, but the underlying code and API can be way easier to understand.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.

duck monster posted:

LET IT BE KNOWN that Symfony can go and eat a bag of dicks. Never let java programmers near your framework people, things can only go wrong.

Hahaha more fool you if you think that the Symfony Bundle standard is the lovely end of the stick. Symfony and Zend are exactly the same in their fat-bitch structure and it's all in an effort to support testing, which they do really quite well.

spiritual bypass
Feb 19, 2008

Grimey Drawer
At least it's Laravel, the lobotomized Symfony with only half its documentation that wants you to pay for videos

duck monster
Dec 15, 2004

v1nce posted:

Hahaha more fool you if you think that the Symfony Bundle standard is the lovely end of the stick. Symfony and Zend are exactly the same in their fat-bitch structure and it's all in an effort to support testing, which they do really quite well.

Maybe its a PHPs rather than symfony problem, but frameworks in other languages, notably Django and Rails, seem to have solved these problems and can do full coverage fully mocked testing without all the bureacracy and without ending up in the lobotomized state Laravel is in (Laravel is actually OK imho, its just that its ORM is garbage and it really needs to swap out its shity regexy template thingo for something like Twig or even Smarty. For *small* sites its great.)

i dunno, I feel like I''ve spent the past your fighting the framework instead of getting projects out the door.

Adbot
ADBOT LOVES YOU

musclecoder
Oct 23, 2006

I'm all about meeting girls. I'm all about meeting guys.
I feel the exact opposite with Symfony (and Doctrine to a lesser extent, which I have a love/hate relationship with). It's completely changed how I build apps, and has allowed me to get many high quality, tested, in-depth projects out into production over the past three years.

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