PHP won't execute a python file - python

I've been getting this problem for a little while now.
The thing is that i have an HTML form proceed by PHP which looks like that:
<?php
if (isset($_POST)) {
$link = mysqli_connect("localhost", "root", "password", "tablename");
$url = $_POST['url'];
$shorturl = str_replace(['/', 'https:', 'http:'], '', $url);
$iconpath = shell_exec("python3 /home/favicon.py {$url}");
$sql = "INSERT INTO links (url, shorturl, iconpath) values ('{$url}', '{$shorturl}', '{$iconpath}')";
$result = mysqli_query($link, $sql);
}
/*
header('Location: /');
exit;
*/
?>
This code is supposed to extract the given URL from the form, execute python file that downloads favicon of the site and insert the data into a MySQL table.Python code:
import sys
import requests
url = sys.argv[1]
img_data = requests.get(f'{url}/favicon.ico').content
iconpath = '/home/favicon.png'
with open(iconpath, 'wb') as handler:
handler.write(img_data)
print(iconpath)
It all works fine except for the favicon part. When i run the python file from shell, it works fine. When i run it from PHP interactive console by the exact same code written in the form handler, it works fine. But it just won't run properly in the handler, because even when i try to debug it like
echo $iconpath;
it doesn't actually show anything in there. What can i do with it?
P.S. the code actually inserts $url and $shorturl variables into the database, so i said it all works fine except the shell_exec part

Related

Add Python Script as a file to AWS SSM Document (YAML)

I'm trying to write a script for a SystemsManager Automation document and would like to keep the Python code in a seperate file so it's easy to invoke on my local machine. For complex scripts they can also be tested using a tool such as unittest.
Example YAML syntax from my SSM Automation:
mainSteps:
- name: RunTestScript
action: aws:executeScript
inputs:
Runtime: python3.8
Handler: handler
InputPayload:
Action: "Create" # This is just a random payload for now I'm only testing
Script: |-
"${script}" # My script should be injected here :)
Note: Yes, I've written the script directly in YAML and it works fine. But I'd like to achieve something similar to:
locals {
script = file("${path.module}/automations/test.py")
}
resource "aws_ssm_document" "aws_test_script" {
name = "test-script"
document_format = "YAML"
document_type = "Automation"
content = templatefile("${path.module}/automations/test.yaml", {
ssm_automation_assume_role = aws_iam_role.ssm_automation.arn
script = local.script
})
}
My console shows that yes the file is being read correctly.
Terraform plan...:
+ "def handler(event, context):
+ print(event)
+ import boto3
+ iam = boto3.client('iam')
+ response = iam.get_role(
+ RoleName='test-role'
+ )
+ print(response)"
Notice how the indentation is broken? My .py file has the correct indentation.
I suspect one of the terraform functions or YAML operators I'm using it breaking the indentation - which is very important for a language such as Python.
If I go ahead and Terraform apply I receive:
Error: Error updating SSM document: InvalidDocumentContent: YAML not well-formed. at Line: 30, Column: 1
I tried changing the last line in my YAML to be Script: "${script}" and I can Terraform Plan and Apply fine, but the Python script is on a single line and fails when executing the automation in AWS.
I've also tried using indent(4, local.script) without success.
Keen to hear/see what ideas and solutions you may have.
Thanks
I noticed my plan output had "'s around the code. So I tried a multiline string in Python """ and it continued to fail. Bearing in mind I assumed SSM was smart enough to strip quotes if it doesn't want them.
Anyway, the mistake was adding quotes around the template variable:
# Mistake
Script: |-
"${script}" # My script should be injected here :)
Solution
Script: |-
${script}
After that I decided okay now that it works, can I remove the indent() method I'm using and I got the YAML not well-formed error back.
So using:
locals {
script = indent(8, file("${path.module}/automations/test.py"))
}
resource "aws_ssm_document" "test_script" {
name = "test-script"
document_format = "YAML"
document_type = "Automation"
content = templatefile("${path.module}/automations/test.yaml", {
ssm_automation_assume_role = aws_iam_role.ssm_automation.arn
script = local.script
})
}
Works great with:
mainSteps:
- name: RunDMSRolesScript
action: aws:executeScript
inputs:
Runtime: python3.8
Handler: handler
InputPayload:
Action: "create"
Script: |-
${script}
If it helps anyone, this is what my SSM Script looks like in the AWS UI when it runs without errors. Formatted correctly and AWS seems to append " around it but turned into "\" when I provided quotes in my YAML template which would've broken the script as it's now a string literal.
"def handler(event, context):
print(event)
import boto3
iam = boto3.client('iam')
response = iam.get_role(
RoleName='test-role'
)
print(response)"
That's one way to lose 3 hours!

How to send a variable from Laravel Controller to a Python script?

$client = new Client();
$a = 'https://scholar.google.com/citations?user=';
$gscID = 'EnegzCwAAAAJ';//for eg
$b = '&hl=en&oi=ao';
$url = $a . $gscID . $b;
$crawler = $client->request('GET', $url);
//python script
$process = new Process(['python', public_path() . '\ext.py'], null, ['SYSTEMROOT' => getenv('SYSTEMROOT'), 'PATH' => getenv("PATH")]);
$process->run();
// executes after the command finishes
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
$out[] = $process->getOutput();
dd($out);
Extracting the tables from the given url webpage
Now I want to pass the $url variable to the python script stored in my public folder because everytime my url changes with different person's ID.
Any help would be really appreciated
Found out an easy solution
$output = shell_exec("python ext.py $url");//ext.py is name of my script and $url is my variable which I want to pass
And then in python script write
import sys
url = sys.argv[1]
You can add script parameters in the array that you are passing to Process.
Here is the doc.https://symfony.com/doc/current/components/process.html#using-features-from-the-os-shell

download an excel file from Bokeh server via "button"

I have a Bokeh directory format like below.
BTSapp.py is my equivalent of 'main.py'
In data folder, I have 1 input (excel) file and 1 output (excel) file. I wrote a script to transform the data from the input file and write it to the output file. I would like to create a bokeh button, which when the end users click they can download the output file.
Can someone please help me? I found this question also on stackoverflow: send file from server to client on bokeh but I couldn't make it work in my case. I kept getting syntax error for JScode_xhr.
Thank you in advance.
I tried myself and below is the correct code. It will also fix the issue of double alert and of the generation of 2 excel files after the js code is activated.
Note: this is an adjusted version from this post
JScode_fetch = """
var filename = 'my_BSS_result.xlsx';
fetch('/app/static/output.xlsx', {cache: "no-store"}).then(response => response.blob())
.then(blob => {
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
var link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
link.target = "_blank";
link.style.visibility = 'hidden';
link.dispatchEvent(new MouseEvent('click'))
URL.revokeObjectURL(url);
}
return response.text();
});
"""

How can I save prestashop invoices automatically and manually?

I want to print out an invoice(pdf) automatically, what's recently saved on the server. And also making manual saving possible
I'm using prestashop 1.6.1 and the invoices are mostly downloaded from the prestashop admin page, but I needed more easier way to print out these invoices, so I made an adminpage for myself it looks like this:
The printer button has a href of the invoice generated address
like:"http://www.example.com/admin/index.php?controller=AdminPdf&submitAction=generateInvoicePDF&id_order=3230"
From the link I can download it and then print it when it's opened in pdf reader, but I want to do this in one click.
Soo... I made an script for automatically printing the pdf when its saved on some specific location
#! /usr/bin/python import os
import os
import time
import os.path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class ExampleHandler(FileSystemEventHandler):
def on_created(self, event):
output=str(event.src_path.replace("./",""))
print(output)
#print event.src_path.replace("./","")
print "Got event for file %s" % event.src_path
os.system("lp -d HL2250DN %s" % output)
observer = Observer()
event_handler = ExampleHandler()
observer.schedule(event_handler, path='.',recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
There is two options to download it automatically to the server
1. Override PDF.php and PDFGenerator.php files like this:
PDF.php
class PDF extends PDFCore
{
public function render($display = true)
{
if($this->template == PDF::TEMPLATE_INVOICE)
parent::render('F', true);
return parent::render($display);
}
}
?>
PDFGenerator.php
<?php
class PDFGenerator extends PDFGeneratorCore
{
public function render($filename, $display = true)
{
if (empty($filename)) {
throw new PrestaShopException('Missing filename.');
}
$this->lastPage();
if ($display === true) {
$output = 'D';
} elseif ($display === false) {
$output = 'S';
} elseif ($display == 'D') {
$output = 'D';
} elseif ($display == 'S') {
$output = 'S';
} elseif ($display == 'F') {
$output = 'F';
$filename = '/folder/for/print_it/'.str_replace("#", "", $filename);
} else {
$output = 'I';
}
return $this->output($filename, $output);
}
}
?>
2. Use script to download
First attempt
The first option worked for automatic saving, but when I tried to save invoices manually I got an blank or broken pdf file. I also tried to change the pdf.php, but it dident work out for me. Also made an post about this: Prestashop saving invoices manually and automatically. No answers were given and I moved on second option.
Second attempt
I tried to download invoices with python script and it worked, but how can I know which one to download?
#!/usr/bin/env python
import requests
import webbrowser
url = "http://www.example.com/admin/index.php?controller=AdminLogin&token=5a01dc4e606bca6c26e95ddea92d3d15"
url2 = "http://www.example.com/admin/index.php?controller=AdminPdf&token=35b276c05aa6f5eb516737a8d534eb66&submitAction=generateInvoicePDF&id_order=3221"
payload = {'example': 'example',
'example': 'example',
'stay_logged_in':'2',
'submitLogin':'1',}
with requests.session() as s:
# fetch the login page
s.get(url)
# post to the login form
r = s.post(url, data=payload)
print(r.text)
response = s.get(url2)
with open('/tmp/metadataa.pdf', 'wb') as f:
f.write(response.content)
Soo the problem with this option is that.. How can I pass the href(what was clicked from the printer button) to url?
Solving this has been really frustrating and I know there is an simple and easy option for this, but I'm still looking for this.
Everytime you generate invoice PDF you are forcing it to be saved as local file.
What you want to do is add an extra GET parameter to the print button and check for its presence in the overriden class so that the PDF only gets stored as local file when you want to print directly.
So first add a GET parameter to print buttons eg. &print=1. Either in your template or wherever you are generating these buttons so that the button's href looks like this:
http://www.example.com/admin/index.php?controller=AdminPdf&submitAction=generateInvoicePDF&id_order=3230&print=1
Now you can check if parameter exists in PDF class and only then force the PDF to be outputted to local file.
class PDF extends PDFCore
{
public function render($display = true)
{
if($this->template == PDF::TEMPLATE_INVOICE && Tools::getValue('print') == 1) {
// Output PDF to local file
parent::render('F');
// Redirect back to the same page so you don't get blank page
Tools::redirectAdmin(Context::getContext()->link->getAdminLink('AdminMyController'));
}
else {
return parent::render($display);
}
}
}
You can keep the overriden PDFGenerator class as is.

Calling python from Actionscript

I have an Adobe Air Program that calls a python script. I dont' think the actionscript 3.0 is making the proper call. Code:
var file:File;
var args:Vector.<String> = new Vector.<String>;
file = new File().resolvePath("/usr/bin/python");
var pyScript:File;
pyScript = File.applicationDirectory.resolvePath("python/mac/merge.py");
var tempOutPath:String = File.applicationStorageDirectory.resolvePath("out.pdf").nativePath;
args.push(pyScript.nativePath, "-w", "-o", tempOutPath, "-i");
for(var x:int; x < numFilesToProcess; x++){
var pdfPath:String = File(pdfs.getItemAt(x)).nativePath;
args.push(pdfPath);
}
callNative(file, args);
In terminal (Mac), the following works fine:
python merge.py -w -o out.pdf -i file1.pdf file2.pdf
The args.push(pyScript.native.... line is the problematic one. I'd appreciate some assistance.
I have faced a similar problem using Air. I needed to print to a receipt printer from an Air app. I couldn't do it from the app itself so I used a python RPC server to do the work for me and talked to it over http. below is a simplified version to give you an idea:
The python RPC server
from SimpleXMLRPCServer import SimpleXMLRPCServer
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
class RequestHandler(SimpleXMLRPCRequestHandler):
rpc_paths = ('/','/RPC2')
server = SimpleXMLRPCServer(('localhost', 8123), requestHandler=RequestHandler)
def myService( arg0, arg1 ):
#do the stuff
return 0
server.register_function(myService)
server.serve_forever()
In Air I create the call as an XML string and make my request.
I haven't shown all the details as I was using javascript not actionscript so please treat this as pseudocode.
// XML as a string
// possibly create the XML and toXMLString() it?
var data:String = '
<?xml version="1.0"?>
<methodCall>
<methodName>myService</methodName>
<params>
<param>
<string>file1.pdf</string>
</param>
<param>
<string>file2.pdf</string>
</param>
</params>
</methodCall>';
var req:URLRequest = new URLRequest('localhost:8123');
rec.method = 'POST';
rec.data = data;
var loader:URLLoader = new URLLoader( req );
//etc

Categories

Resources