Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python to php translator, compile python script to php
import ast
from cStringIO import StringIO
import sys
INFSTR = '1e308'
def interleave(inter, f, seq):
seq = iter(seq)
try:
f(next(seq))
except StopIteration:
pass
else:
for x in seq:
inter()
f(x)
class PythonToPhp:
def __init__(self, source, indent = 0):
tree = ast.parse(source)
self.code = StringIO()
self.tabstop = 2
self._indent = indent
self.dispatch(tree)
def get_code(self):
return self.code.getvalue()
def fill(self, text = ''):
self.code.write('\n%s%s' % (' ' * self.tabstop * self._indent, text))
def write(self, text):
self.code.write(text)
def enter(self):
self.code.write(' {')
self._indent += 1
def leave(self):
self._indent -= 1
self.fill('}')
def error(self, msg):
print msg
sys.exit()
def dispatch(self, tree):
if isinstance(tree, list):
for t in tree:
self.dispatch(t)
return
meth = getattr(self, '_%s' % tree.__class__.__name__)
return meth(tree)
########## Transform Methods ##########
def _Module(self, tree):
for stmt in tree.body:
self.dispatch(stmt)
### Statement ###
def _Expr(self, tree):
self.fill()
self.dispatch(tree.value)
self.write(';')
def _Import(self, t):
self.error('import not supported')
def _ImportFrom(self, t):
self.error('import not supported')
def _Assign(self, t):
self.fill()
for target in t.targets:
if isinstance(target, ast.Tuple):
self._lvalue_tuple(target)
else:
self.dispatch(target)
self.write(' = ')
self.dispatch(t.value)
self.write(';')
def _AugAssign(self, t):
self.fill()
self.dispatch(t.target)
name = t.op.__class__.__name__
if name == 'Pow':
self.write(' = pow(')
self.dispatch(t.target)
self.write(', ')
self.dispatch(t.value)
self.write(');')
elif name == 'FloorDiv':
self.write(' = floor(')
self.dispatch(t.target)
self.write(' / ')
self.dispatch(t.value)
self.write(');')
else:
self.write(' %s= ' % self.binop[t.op.__class__.__name__])
self.dispatch(t.value)
self.write(';')
def _Return(self, t):
self.fill('return')
if t.value:
self.write(' ')
self.dispatch(t.value)
self.write(';')
def _Pass(self, t):
self.fill(';')
def _Break(self, t):
self.fill('break;')
def _Continue(self, t):
self.fill('continue;')
def _Delete(self, t):
for target in t.targets:
self.fill('unset(')
self.dispatch(target)
self.write(');')
def _Assert(self, t):
self.fill('assert(')
self.dispatch(t.test)
self.write(');')
def _Exec(self, t):
self.fill('eval(')
self.dispatch(t.body)
self.write(');')
def _Print(self, t):
self.fill('echo ')
sep = ''
for e in t.values:
self.write(sep)
self.dispatch(e)
sep = ', '
if t.nl:
self.write(sep)
self.write("'<br />'")
self.write(';')
def _Global(self, t):
self.fill('global ')
interleave(lambda: self.write(', '), self.write, t.names)
self.write(';')
def _Yield(self, t):
self.error('yield not supported')
def _Raise(self, t):
self.error('Exceptions not supported')
def _TryExcept(self, t):
self.error('Exceptions not supported')
def _TryFinally(self, t):
self.error('Exceptions not supported')
def _ExceptHandler(self, t):
self.error('Exceptions not supported')
def _ClassDef(self, t):
self.error('Class not supported')
def _FunctionDef(self, t):
self.fill('function ' + t.name + '(')
self.dispatch(t.args)
self.write(')')
self.enter()
self.dispatch(t.body)
self.leave()
def _For(self, t):
self.fill('foreach (')
self.dispatch(t.iter)
self.write(' as ')
self.dispatch(t.target)
self.write(')')
self.enter()
self.dispatch(t.body)
self.leave()
if t.orelse:
self.error('else clause for for statement not supported')
def _If(self, t):
self.fill("if (")
self.dispatch(t.test)
self.write(')')
self.enter()
self.dispatch(t.body)
self.leave()
# collapse nested ifs into equivalent elifs.
while (t.orelse and len(t.orelse) == 1 and
isinstance(t.orelse[0], ast.If)):
t = t.orelse[0]
self.fill("elseif (")
self.dispatch(t.test)
self.write(')')
self.enter()
self.dispatch(t.body)
self.leave()
# final else
if t.orelse:
self.fill("else")
self.enter()
self.dispatch(t.orelse)
self.leave()
def _While(self, t):
self.fill("while (")
self.dispatch(t.test)
self.write(')')
self.enter()
self.dispatch(t.body)
self.leave()
if t.orelse:
self.error('else clause for while statement not supported')
def _With(self, t):
self.error('with statement not supported')
### Expression ###
def _Str(self, t):
self.write(repr(t.s))
def _Name(self, t):
if t.id == 'True':
self.write('true')
elif t.id == 'False':
self.write('false')
elif t.id == 'None':
self.write('null')
else:
self.write('$%s' % t.id)
def _Repr(self, t):
self.write('var_export(')
self.dispatch(t.value)
self.write(", true)")
def _Num(self, t):
repr_n = repr(t.n)
if repr_n.startswith('-'):
self.write('(')
self.write(repr_n.replace('inf', INFSTR))
if repr_n.startswith('-'):
self.write(')')
def _List(self, t):
self.write('array(')
interleave(lambda: self.write(", "), self.dispatch, t.elts)
self.write(')')
def _ListComp(self, t):
if len(t.generators) > 1:
self.error('multiple generators in comprehension not supported')
generator = t.generators.pop()
self._comprehension(generator, 'left')
self.dispatch(t.elt)
self._comprehension(generator, 'right')
def _comprehension(self, t, part = 'left'):
if part == 'left':
if t.ifs:
self.write('array_filter(array_map(function(')
else:
self.write('array_map(function(')
self.dispatch(t.target)
self.write(') { return ')
elif part == 'right':
self.write('; }, ')
self.dispatch(t.iter)
if t.ifs:
self.write('), function(')
self.dispatch(t.target)
self.write(') { return ')
for if_clause in t.ifs:
self.dispatch(if_clause)
self.write('; })')
else:
self.write(')')
def _GeneratorExp(self, t):
if len(t.generators) > 1:
self.error('multiple generators in comprehension not supported')
generator = t.generators.pop()
self._comprehension(generator, 'left')
self.dispatch(t.elt)
self._comprehension(generator, 'right')
def _SetComp(self, t):
if len(t.generators) > 1:
self.error('multiple generators in comprehension not supported')
self.write('array_unique(')
generator = t.generators.pop()
self._comprehension(generator, 'left')
self.dispatch(t.elt)
self._comprehension(generator, 'right')
self.write(')')
def _DictComp(self, t):
self.error('dict comprehension not supported')
def _IfExp(self, t):
self.write("((")
self.dispatch(t.test)
self.write(') ? (')
self.dispatch(t.body)
self.write(') : (')
self.dispatch(t.orelse)
self.write('))')
def _Set(self, t):
assert(t.elts) # should be at least one element
self.write('array_unique(array(')
interleave(lambda: self.write(", "), self.dispatch, t.elts)
self.write('))')
def _Dict(self, t):
self.write('array(')
def write_pair(pair):
k, v = pair
self.dispatch(k)
self.write(' => ')
self.dispatch(v)
interleave(lambda: self.write(', '), write_pair, zip(t.keys, t.values))
self.write(')')
def _Tuple(self, t):
self.write('array(')
interleave(lambda: self.write(", "), self.dispatch, t.elts)
self.write(')')
def _lvalue_tuple(self, t):
self.write('list(')
interleave(lambda: self.write(", "), self.dispatch, t.elts)
self.write(')')
unop = {"Invert":"~", "Not": "!", "UAdd":"+", "USub":"-"}
def _UnaryOp(self, t):
self.write("(")
self.write(self.unop[t.op.__class__.__name__])
self.write(" ")
if isinstance(t.op, ast.USub) and isinstance(t.operand, ast.Num):
self.write("(")
self.dispatch(t.operand)
self.write(")")
else:
self.dispatch(t.operand)
self.write(")")
binop = {
"Add":"+",
"Sub":"-",
"Mult":"*",
"Div":"/",
"Mod":"%",
"LShift":"<<",
"RShift":">>",
"BitOr":"|",
"BitXor":"^",
"BitAnd":"&",
}
def _BinOp(self, t):
name = t.op.__class__.__name__
if name == 'Pow':
self.write("(pow(")
self.dispatch(t.left)
self.write(', ')
self.dispatch(t.right)
self.write('))')
elif name == 'FloorDiv':
self.write('(floor(')
self.dispatch(t.left)
self.write(' / ')
self.dispatch(t.right)
self.write('))')
elif name == 'Mod' and isinstance(t.left, ast.Str):
self.write('sprintf(')
self.dispatch(t.left)
self.write(', ')
if isinstance(t.right, ast.Str):
self.dispatch(t.right)
elif isinstance(t.right, ast.Tuple):
interleave(lambda: self.write(", "), self.dispatch, t.right.elts)
else:
self.error('impossible string substript error')
self.write(')')
else:
self.write("(")
self.dispatch(t.left)
self.write(" " + self.binop[name] + " ")
self.dispatch(t.right)
self.write(")")
cmpops = {
"Eq":"==",
"NotEq":"!=",
"Lt":"<",
"LtE":"<=",
"Gt":">",
"GtE":">=",
"Is":"===",
"IsNot":"!==",
}
def _Compare(self, t):
name = t.ops[0].__class__.__name__
self.write("(")
if name == 'In':
comparator = t.comparators.pop()
self.write('in_array(')
self.dispatch(t.left)
self.write(', ')
self.dispatch(comparator)
self.write(') || array_key_exists(')
self.dispatch(t.left)
self.write(', ')
self.dispatch(comparator)
self.write(')')
elif name == 'NotIn':
comparator = t.comparators.pop()
self.write('!in_array(')
self.dispatch(t.left)
self.write(', ')
self.dispatch(comparator)
self.write(') && !array_key_exists(')
self.dispatch(t.left)
self.write(', ')
self.dispatch(comparator)
self.write(')')
else:
self.dispatch(t.left)
for o, e in zip(t.ops, t.comparators):
self.write(" " + self.cmpops[o.__class__.__name__] + " ")
self.dispatch(e)
self.write(")")
boolops = {ast.And: '&&', ast.Or: '||'}
def _BoolOp(self, t):
self.write("(")
s = " %s " % self.boolops[t.op.__class__]
interleave(lambda: self.write(s), self.dispatch, t.values)
self.write(")")
def _Attribute(self,t):
self.dispatch(t.value)
self.write("->")
self.write(t.attr)
def _func_name(self, t):
self.write('%s' % t.id)
def _Call(self, t):
self._func_name(t.func)
self.write("(")
comma = False
for e in t.args:
if comma: self.write(", ")
else: comma = True
self.dispatch(e)
for e in t.keywords:
if comma: self.write(", ")
else: comma = True
self.dispatch(e)
if t.starargs:
self.error('function vararg not supported')
if t.kwargs:
self.error('function kwarg not supported')
self.write(")")
def _Subscript(self, t):
if isinstance(t.slice, ast.Index):
#self.dispatch(t.value)
#self.write("[")
#self.dispatch(t.slice)
#self.write("]")
self.write('pyphp_subscript(')
self.dispatch(t.value)
self.write(', ')
self.dispatch(t.slice)
self.write(')')
elif isinstance(t.slice, ast.Slice):
self.write('array_slice(')
self.dispatch(t.value)
self.write(', ')
self.dispatch(t.slice)
self.write(')')
def _Ellipsis(self, t):
self.error('ellipsis not supported')
def _Index(self, t):
self.dispatch(t.value)
def _Slice(self, t):
if t.lower:
self.dispatch(t.lower)
else:
self.write('0')
if t.upper:
self.write(", ")
self.write('(')
self.dispatch(t.upper)
self.write(' - ')
if t.lower:
self.dispatch(t.lower)
else:
self.write('0')
self.write(')')
if t.step:
self.error('slice step not supported')
def _ExtSlice(self, t):
self.error('extslice not supported')
#interleave(lambda: self.write(', '), self.dispatch, t.dims)
### Others ###
def _arguments(self, t):
first = True
defaults = [None] * (len(t.args) - len(t.defaults)) + t.defaults
for a,d in zip(t.args, defaults):
if first: first = False
else: self.write(", ")
self.dispatch(a),
if d:
self.write(" = ")
self.dispatch(d)
if t.vararg:
self.error('function vararg not supported')
if t.kwarg:
self.error('function kwarg not supported')
def _keyword(self, t):
self.write('$%s' % t.arg)
self.write(" = ")
self.dispatch(t.value)
def _Lambda(self, t):
self.write("(")
self.write("function(")
self.dispatch(t.args)
self.write(") {")
self.dispatch(t.body)
self.write("})")
def _alias(self, t):
self.error('alias not supported')
@jucier

This comment has been minimized.

Copy link

jucier commented Sep 19, 2015

d

@ratze90

This comment has been minimized.

Copy link

ratze90 commented Aug 5, 2016

Hey reusee,

nice and useful script, but how do i call it, if i want to convert my python_to_php_source_file.py to python_to_php_target_file.php?

Thanks,

ratze90 :) 👍

@vahidvdn

This comment has been minimized.

Copy link

vahidvdn commented Feb 6, 2017

Any example for using this?

@bitsnaps

This comment has been minimized.

Copy link

bitsnaps commented Apr 29, 2017

here is a simple usage:

s = 'print("ok")'
py2php = PythonToPhp(s)
print py2php.get_code()

this will output:
echo 'ok', '<br />';

@smartleopard

This comment has been minimized.

Copy link

smartleopard commented Oct 25, 2017

Hello, first of all thank you for sharing this code. But why did PythonToPhp undefined? I tried several times. Second question, can I use this code to convert a whole .py script? Thank you for helping me. Really appreciate your help.

@bplancher

This comment has been minimized.

Copy link

bplancher commented Jan 3, 2018

Hello (and happy new year !) !

Thanks for this useful code ^^

If i can add my 2 cents, i propose you to add those few lines at the end of your file, so that it can be used in command-line directly (this is a very quick and not good-practice-proof implementation, but still working):

if __name__ == '__main__':
    if sys.argv[1:]:
        with open(sys.argv[1], 'r') as srcfile:
            ret = PythonToPhp(srcfile.read())
            print ret.code.getvalue()
@ashbeats

This comment has been minimized.

Copy link

ashbeats commented Feb 17, 2018

Created 7 years ago

@agnius-vasiliauskas

This comment has been minimized.

Copy link

agnius-vasiliauskas commented Mar 18, 2019

When I try to convert this code to PHP :

def ln(x):
    n = 1000.0
    return n * ((x ** (1/n)) - 1)
def calcNumEntropyBits(s):
        if len(s) <= 0: return 0.0
        symCount = {}
        for c in s:
                if c not in symCount: symCount[c] = 1
                else: symCount[c] += 1
        entropy = 0.0
        for c,n in symCount.iteritems():
                prob = n / float(len(s))
                entropy += prob * (ln(prob)/ln(2))
        if entropy >= 0.0: return 0.0
        else: return -(entropy*len(s))

def testEntropy(s):
        print "Bits of entropy in '%s' is %.2f" % (s, calcNumEntropyBits(s))

testEntropy('hello world')
testEntropy('bubba dubba')
testEntropy('aaaaaaaaaaa')
testEntropy('aaaaabaaaaa')
testEntropy('abcdefghijk')

I get a translator error :

py2php = PythonToPhp(s)
File "/py2php/py2php.py", line 25, in init
self.dispatch(tree)
File "/py2php/py2php.py", line 54, in dispatch
return meth(tree)
File "/py2php/py2php.py", line 60, in _Module
self.dispatch(stmt)
File "/py2php/py2php.py", line 54, in dispatch
return meth(tree)
File "/py2php/py2php.py", line 179, in _FunctionDef
self.dispatch(t.body)
File "/py2php/py2php.py", line 51, in dispatch
self.dispatch(t)
File "/py2php/py2php.py", line 54, in dispatch
return meth(tree)
File "/py2php/py2php.py", line 184, in _For
self.dispatch(t.iter)
File "/py2php/py2php.py", line 54, in dispatch
return meth(tree)
File "/py2php/py2php.py", line 464, in _Call
self._func_name(t.func)
File "/py2php/py2php.py", line 461, in _func_name
self.write('%s' % t.id)
AttributeError: 'Attribute' object has no attribute 'id'

Can you fix this converter error ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.