hybrid PHP + R architecture

59 views
Skip to first unread message

jacktanner

unread,
Nov 15, 2009, 10:11:34 PM11/15/09
to rapache
What's the right way to structure my hybrid PHP + R application? I've
got a large-ish PHP code base (using Zend Framework). Among other
things, it sets up a database connection to one of several databases,
imposes access controls on users, and writes some raw numbers to the
database that I'd like to graph using R.

If I expose a rapache instance to the web, do I need to re-implement
in R the database connection piece (because the database is a
parameter), and the access control piece (because only some users may
view the graphs)? Or is there a way to use the existing PHP to pass
the selected database and credentials to R? I hope to minimize the
amount of R I have to write, and b) to make sure that the users cannot
manipulate the database selection and credentials to bypass the access
controls.

My best idea so far is to set encrypted cookies in PHP for the
database selection and credentials, and then to decrypt the cookies on
the R side. Am I on the wrong track?

Jeffrey Horner

unread,
Nov 16, 2009, 9:30:05 AM11/16/09
to rap...@googlegroups.com

I'm no security expert, but encrypting credentials and storing them in a
cookie seems a bit insecure.

I've had success with just using rapache as a trusted web service. I
implement this by running another instance of apache on a non-standard
port on the same machine and only accept connections from the localhost.
Then the public apache server running my php app will use curl to access
the trusted web service.

Jeff
--
http://biostat.mc.vanderbilt.edu/JeffreyHorner

jacktanner

unread,
Nov 16, 2009, 11:28:47 AM11/16/09
to rapache
On Nov 16, 9:30 am, Jeffrey Horner <jeff.hor...@vanderbilt.edu> wrote:
> I'm no security expert, but encrypting credentials and storing them in a
> cookie seems a bit insecure.

I imagine one could implement this securely. Use a salt when
encrypting, expire the cookie after a little while, etc. But this is
starting to turn into a lot of implementation overhead.

> I've had success with just using rapache as a trusted web service. I
> implement this by running another instance of apache on a non-standard
> port on the same machine and only accept connections from the localhost.
> Then the public apache server running my php app will use curl to access
> the trusted web service.

This is clever and simple. And then the output of curl is embedded in
the PHP? What if the output is an image?

Jeffrey Horner

unread,
Nov 16, 2009, 11:58:58 AM11/16/09
to rap...@googlegroups.com

Here's some PHP pseudocode which retrieves a PDF from rapache. You can
do the same thing for an image as well.

# Call an SSL basic authenticated rapache service with a post payload
# Arguments:
# $service - a string which names the service. just appended to
$rapache_server
# $opt - name/value pairs to place in the post payload
# $post_data - the post payload, rapache_service() passes as is.
# $debug - place debugging info in html comment
function rapache_service($service,$opt=NULL,$post_data=NULL,$debug=FALSE){
$rapache_server = 'http://yourserverhere.com';
$html = '';
$ch = curl_init();
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt ($ch, CURLOPT_URL, "$rapache_server/$service");
curl_setopt ($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
curl_setopt ($ch, CURLOPT_HEADER, 0);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt ($ch, CURLOPT_USERPWD, "${RAPACHE_USER}:${RAPACHE_PASS}");
if (!is_null($opt) || !is_null($post_data)){
curl_setopt ($ch,CURLOPT_POST,1);
if (!is_null($opt)){
foreach( $opt as $k => $v ) $post[ ] = sprintf( "%s=%s",
$k, urlencode( $v ) );
$post_data=implode('&',$post);
}
curl_setopt ($ch,CURLOPT_POSTFIELDS,$post_data);
}
$html = curl_exec ($ch);
if ($debug){
$html = '<!-- curl: ' .
curl_getinfo($ch,CURLINFO_EFFECTIVE_URL). ' '. curl_error($ch) . '-->' .
$html;
}
curl_close ($ch);
return $html;
}

# In this call, the post payload is constructed by
# rapache_fields_to_csv(): a function that connects
# to a database and constructs a CSV string.
#
# The service is HmiscDescPDF which uses the Hmisc package
# to construct a PDF with latex and the describe function.

$pdf = rapache_service('HmiscDescPDF', NULL, "${app_title}:
${form_desc}\n".rapache_fields_to_csv($app_name,$form,$totalrecs,$user_rights['group_id']));

header("Expires: 0");
if(isset($_SERVER['HTTP_USER_AGENT']) &&
strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')){
error_log("detected IE",0);
#header('Content-Type: application/force-download');
header('Content-type: application/pdf');
header("Cache-Control: cache");
header("Pragma: cache");
} else {
header("cache-control: no-store, no-cache, must-revalidate");
header("Pragma: no-cache");
header('Content-Type: application/octet-stream');
}
header('Content-Length: '.strlen($pdf));
header('Content-disposition: attachment; filename="'.$pdfname.'"');
print $pdf;

Jeff
--
http://biostat.mc.vanderbilt.edu/JeffreyHorner

Jeffrey Horner

unread,
Nov 16, 2009, 12:01:40 PM11/16/09
to rap...@googlegroups.com

Oops! that should have been https instead of http.

Jeff

jacktanner

unread,
Nov 16, 2009, 9:15:50 PM11/16/09
to rapache
Thanks for the code! Do you think it's necessary to use https for this
configuration, localhost to localhost?

On Nov 16, 12:01 pm, Jeffrey Horner <jeff.hor...@vanderbilt.edu>
wrote:

jacktanner

unread,
Nov 16, 2009, 11:04:29 PM11/16/09
to rapache
Furthermore, do you think one could get by with a VirtualHost on a
separate port rather than having to run a second httpd?

Jeffrey Horner

unread,
Nov 17, 2009, 9:07:33 AM11/17/09
to rap...@googlegroups.com
On Mon, Nov 16, 2009 at 10:04 PM, jacktanner <ih...@hotmail.com> wrote:
>
> Furthermore, do you think one could get by with a VirtualHost on a
> separate port rather than having to run a second httpd?
>
> On Nov 16, 9:15 pm, jacktanner <i...@hotmail.com> wrote:
>> Thanks for the code! Do you think it's necessary to use https for this
>> configuration, localhost to localhost?

Answering both questions. No, you really don't need https if you're
only allowing trusted connections from localhost. And yes, I think the
virtual host on another port will work. Be sure to configure your
firewall to only allow connections from localhost on your port.

Jeff

>>
>> On Nov 16, 12:01 pm, Jeffrey Horner <jeff.hor...@vanderbilt.edu>
>> wrote:
>>
>> > Jeffrey Horner wrote on 11/16/2009 10:58 AM:
>>
>> > Oops! that should have been https instead of http.
>>
>> > Jeff
> >
>



--
http://biostat.mc.vanderbilt.edu/JeffreyHorner

jacktanner

unread,
Nov 17, 2009, 10:15:12 AM11/17/09
to rapache
For that matter, I don't think you need a separate (or additional)
port or a firewall restriction. I just did <VirtualHost 127.0.0.1> and
that seems to be sufficient to restrict access. Am I missing
something?

I think there's a bug in the code you posted: no matter whether
$post_data has a value when rapache_service() is called, its value
will get overwritten after the foreach over $opt.

On Nov 17, 9:07 am, Jeffrey Horner <jeffrey.hor...@vanderbilt.edu>
wrote:

Jeffrey Horner

unread,
Nov 18, 2009, 10:33:21 AM11/18/09
to rap...@googlegroups.com
On Tue, Nov 17, 2009 at 9:15 AM, jacktanner <ih...@hotmail.com> wrote:
>
> For that matter, I don't think you need a separate (or additional)
> port or a firewall restriction. I just did <VirtualHost 127.0.0.1> and
> that seems to be sufficient to restrict access. Am I missing
> something?
>
> I think there's a bug in the code you posted: no matter whether
> $post_data has a value when rapache_service() is called, its value
> will get overwritten after the foreach over $opt.


Are you sure? I've looked over it and it seems sound to me:

# If one of $opt or $post_data are not null, then we will send a post payload
if (!is_null($opt) || !is_null($post_data)){

curl_setopt ($ch,CURLOPT_POST,1);

# If $opt is not null, then the post payload will consist of $opt
if (!is_null($opt)){
foreach( $opt as $k => $v ) $post[ ] = sprintf( "%s=%s",
$k, urlencode( $v ) );
$post_data=implode('&',$post);
}


# Otherwise use the $post_data
curl_setopt ($ch,CURLOPT_POSTFIELDS,$post_data);
}


Jeff

> On Nov 17, 9:07 am, Jeffrey Horner <jeffrey.hor...@vanderbilt.edu>
> wrote:
>>
>> Answering both questions. No, you really don't need https if you're
>> only allowing trusted connections from localhost. And yes, I think the
>> virtual host on another port will work. Be sure to configure your
>> firewall to only allow connections from localhost on your port.
>
> --~--~---------~--~----~------------~-------~--~----~
> You received this message because you are subscribed to the Google Groups "rapache" group.
> To post to this group, send email to rap...@googlegroups.com
> To unsubscribe from this group, send email to rapache+u...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/rapache?hl=en
> -~----------~----~----~----~------~----~------~--~---
>
>



--
http://biostat.mc.vanderbilt.edu/JeffreyHorner

jacktanner

unread,
Nov 18, 2009, 10:45:27 AM11/18/09
to rapache
Right, we're in agreement. The point is that if both $opt and
$post_data are not null when the function is called, only $opt will
get used, and $post_data will be discarded. This may not be apparent
from the method signature.

In any case, thank you for posting this, it's very helpful.

On Nov 18, 10:33 am, Jeffrey Horner <jeffrey.hor...@vanderbilt.edu>
wrote:
>

Jeffrey Horner

unread,
Nov 18, 2009, 10:59:37 AM11/18/09
to rap...@googlegroups.com
That's why it's pseudocode ;) It's up to the reader to adapt it to
his/her needs.

Best,

Jeff
> --
>
> You received this message because you are subscribed to the Google Groups "rapache" group.
> To post to this group, send email to rap...@googlegroups.com.
> To unsubscribe from this group, send email to rapache+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/rapache?hl=.
>
>
>



--
http://biostat.mc.vanderbilt.edu/JeffreyHorner
Reply all
Reply to author
Forward
0 new messages