├── src ├── __init__.py ├── test_scripts │ ├── __init__.py │ └── Caption.php └── php2python.py ├── setup.cfg ├── LICENSE.txt ├── setup.py ├── .gitignore └── README.md /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/test_scripts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 mgp25 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | import os 3 | 4 | 5 | __version__ = "0.0.1" 6 | __author__ = "Nyaundi Brian" 7 | 8 | 9 | with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme: 10 | README = readme.read() 11 | 12 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 13 | 14 | setuptools.setup( 15 | name='convert2php', 16 | packages=setuptools.find_packages(), 17 | entry_points={ 18 | 'console_scripts': [ 19 | 'convert2php = src.php2python:main' 20 | ] 21 | }, 22 | version=__version__, 23 | description='A python script to convert simple php code to python', 24 | author='Nyaundi Brian', 25 | author_email='ndieksman@gmail.com', 26 | url='https://github.com/danleyb2/php2python', 27 | download_url='https://github.com/danleyb2/php2python/tarball/0.0.1', 28 | keywords=['php', 'python', 'convert'], 29 | include_package_data=True, 30 | zip_safe=False, 31 | license='MIT', 32 | long_description=README, 33 | platforms='any', 34 | install_requires=[], 35 | classifiers=[ 36 | #'Development Status :: 1 - Alpha', 37 | 'Environment :: Console', 38 | 'Intended Audience :: Developers', 39 | 'License :: OSI Approved :: MIT License', 40 | 'Operating System :: OS Independent', 41 | 'Programming Language :: Python', 42 | 'Programming Language :: Python :: 2.7', 43 | ], 44 | ) 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | 3 | 4 | 5 | 6 | ### Python template 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | env/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *,cover 52 | .hypothesis/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # dotenv 85 | .env 86 | 87 | # virtualenv 88 | .venv/ 89 | venv/ 90 | ENV/ 91 | 92 | # Spyder project settings 93 | .spyderproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP to PYTHON 2 | 3 | 4 | A python script to convert simple php code to python, 5 | It just converts the basic syntax 6 | It is the one i use in the conversion mpg25/Instagram-API in PHP to danleyb2/Instagram-API in PYTHON 7 | 8 | ## Installation 9 | ``` 10 | 11 | pip install convert2php 12 | ``` 13 | 14 | ## usage 15 | ``` 16 | $ python php2python.py -h 17 | 18 | usage: php2python.py [-h] -s SCRIPT [-o] 19 | 20 | PHP to PYTHON syntax converter. 21 | 22 | optional arguments: 23 | -h, --help show this help message and exit 24 | -s SCRIPT, --script SCRIPT 25 | Path to PHP script 26 | -o, --overwrite Overwrite Python script if exists 27 | 28 | 29 | ``` 30 | 31 | ``` 32 | $ python php2python.py -s test_scripts/Caption.php 33 | 34 | Converting: test_scripts/Caption.php. Output file will be: test_scripts/Caption.py 35 | # Remove opening and closing to self. 37 | # convert :: to . 38 | # delete all } 39 | # delete namespace|require_once|include_once 40 | # convert protected $var to self.var = None then move into __init__ 41 | # convert public|protected function to def 42 | # add `self` to function signatures 43 | # classes not children to extend `object` 44 | # convert $ to '' 45 | # convert ; to '' 46 | # convert new to '' 47 | Converted: test_scripts/Caption.php. to: test_scripts/Caption.py. { Go on, Proof Check :) } 48 | 49 | 50 | ``` 51 | 52 | ``` 53 | $ python php2python.py -s test_scripts/Caption.php 54 | Sorry, A python Script test_scripts/Caption.py already exist, use -o to overwrite. 55 | 56 | ``` -------------------------------------------------------------------------------- /src/test_scripts/Caption.php: -------------------------------------------------------------------------------- 1 | status = $data['status']; 22 | $this->user_id = $data['user_id']; 23 | $this->created_at_utc = $data['created_at_utc']; 24 | $this->created_at = $data['created_at']; 25 | $this->bit_flags = $data['bit_flags']; 26 | $this->user = new User($data['user']); 27 | $this->content_type = $data['content_type']; 28 | $this->text = $data['text']; 29 | $this->media_id = $data['media_id']; 30 | $this->pk = $data['pk']; 31 | $this->type = $data['type']; 32 | } 33 | 34 | public function getStatus() 35 | { 36 | return $this->status; 37 | } 38 | 39 | protected function getUserId() 40 | { 41 | return $this->user_id; 42 | } 43 | 44 | public function getCreatedAtUtc() 45 | { 46 | return $this->created_at_utc; 47 | } 48 | 49 | public function getCreatedAt() 50 | { 51 | return $this->created_at; 52 | } 53 | 54 | public function getBitFlags() 55 | { 56 | return $this->bit_flags; 57 | } 58 | 59 | public function getUser() 60 | { 61 | return $this->user; 62 | } 63 | 64 | public function getContentType() 65 | { 66 | return $this->content_type; 67 | } 68 | 69 | public function getText() 70 | { 71 | return $this->text; 72 | } 73 | 74 | public function getMediaId() 75 | { 76 | return $this->media_id; 77 | } 78 | 79 | public function getUsernameId() 80 | { 81 | return $this->pk; 82 | } 83 | 84 | public function getType() 85 | { 86 | return $this->type; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/php2python.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python2.7 2 | 3 | import argparse 4 | import fileinput 5 | import logging 6 | import os 7 | import re 8 | import shutil 9 | import sys 10 | 11 | # create logger 12 | logger = logging.getLogger('php2python') 13 | 14 | debug = True 15 | 16 | # console handler 17 | ch = logging.StreamHandler() 18 | if debug: 19 | logger.setLevel(logging.DEBUG) 20 | else: 21 | logger.setLevel(logging.INFO) 22 | 23 | ch.setLevel(logging.DEBUG) 24 | 25 | formatter1 = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 26 | formatter2 = logging.Formatter('%(levelname)s - %(message)s') 27 | 28 | ch.setFormatter(formatter2) 29 | 30 | logger.addHandler(ch) 31 | 32 | declarations = [] 33 | in_foreach = False 34 | in_if = False 35 | last_indent = None 36 | 37 | 38 | def python_script_name(php_script): 39 | return php_script.split('.php')[0] + '.py' 40 | 41 | 42 | def replace(f, o, n): 43 | php_file = fileinput.FileInput(f, inplace=True) 44 | for line in php_file: 45 | # sys.stdout.write('new text') 46 | sys.stdout.write(line.replace(o, n)) 47 | 48 | php_file.close() 49 | 50 | 51 | def remove_lines_bound(f, start, end=None, ignore_leading_spaces=True): 52 | php_file = fileinput.FileInput(f, inplace=True) 53 | end = '[' + end + ']$' if end else '' 54 | if ignore_leading_spaces: 55 | reg = '^(( )*' + start + ').*' + end 56 | else: 57 | reg = '^' + start + '.*' + end 58 | for line in php_file: 59 | if re.match(reg, line): 60 | continue 61 | 62 | sys.stdout.write(line) 63 | 64 | php_file.close() 65 | 66 | 67 | def add_self_to_functions(f): 68 | process_class_declarations(f) 69 | 70 | php_file = fileinput.FileInput(f, inplace=True) 71 | for line in php_file: 72 | reg = r'(.*)(public|protected) function (.*)\((.*)\)' 73 | match = re.match(reg, line) 74 | if match: 75 | 76 | groups = match.groups() 77 | function_indent = groups[0] 78 | function_name = '__init__' if groups[2] == '__construct' else groups[2] 79 | function_params = '(self,' + groups[3] + '):' if groups[3] else '(self):' 80 | 81 | function = function_indent + 'def ' + function_name + function_params + "\n" 82 | sys.stdout.write(function) 83 | 84 | if groups[2] == '__construct': 85 | for declaration in declarations: 86 | sys.stdout.write(declaration) 87 | #sys.stdout.write("") 88 | # todo case of no constructor 89 | else: 90 | sys.stdout.write(line) 91 | 92 | php_file.close() 93 | 94 | 95 | def process_class_declarations(f): 96 | php_file = fileinput.FileInput(f, inplace=True) 97 | for line in php_file: 98 | reg = r'(.*)(public|protected) \$(.*);$' 99 | match = re.match(reg, line) 100 | if match: 101 | 102 | groups = match.groups() 103 | declaration_indent = groups[0] 104 | declaration = (declaration_indent * 2) + 'self.' + groups[2] + ' = None\n' 105 | 106 | declarations.append(declaration) 107 | continue 108 | else: 109 | sys.stdout.write(line) 110 | 111 | php_file.close() 112 | 113 | 114 | def class_definition(f): 115 | php_file = fileinput.FileInput(f, inplace=True) 116 | for line in php_file: 117 | reg = r'class (\w+)( extends (\w+)|)' 118 | match = re.match(reg, line) 119 | if match: 120 | groups = match.groups() 121 | class_name = groups[0] 122 | class_parent = groups[2] or 'object' 123 | if groups[2]: 124 | logger.warning("You need to import " + groups[2]) 125 | 126 | class_def = 'class ' + class_name + '(' + class_parent + '):\n' 127 | sys.stdout.write(class_def) 128 | 129 | else: 130 | sys.stdout.write(line) 131 | 132 | php_file.close() 133 | 134 | 135 | def process_if(py_script): 136 | php_file = fileinput.FileInput(py_script, inplace=True) 137 | for line in php_file: 138 | reg = r'(.*)if(.*)\((.*)\)(.*)\{$' 139 | match = re.match(reg, line) 140 | if match: 141 | groups = match.groups() 142 | if_indent = groups[0] 143 | if_line = if_indent + 'if ' + groups[2] + ':\n' 144 | sys.stdout.write(if_line) 145 | else: 146 | sys.stdout.write(line) 147 | 148 | php_file.close() 149 | 150 | 151 | def process_else(py_script): 152 | php_file = fileinput.FileInput(py_script, inplace=True) 153 | for line in php_file: 154 | reg = r'(.*)\}(.*)else(.*)(.*)\{$' 155 | match = re.match(reg, line) 156 | if match: 157 | groups = match.groups() 158 | else_indent = groups[0] 159 | else_line = else_indent + 'else:\n' 160 | sys.stdout.write(else_line) 161 | else: 162 | sys.stdout.write(line) 163 | 164 | php_file.close() 165 | 166 | 167 | def process_foreach(py_script): 168 | php_file = fileinput.FileInput(py_script, inplace=True) 169 | for line in php_file: 170 | reg = r'(.*)foreach(.*)\((.*) as (.*)\)(.*)\{$' 171 | match = re.match(reg, line) 172 | if match: 173 | 174 | groups = match.groups() 175 | foreach_indent = groups[0] 176 | needle = groups[3] 177 | haystack = groups[2] 178 | foreach_line = foreach_indent+'for '+needle + ' in '+haystack+' :\n' 179 | 180 | sys.stdout.write(foreach_line) 181 | else: 182 | sys.stdout.write(line) 183 | 184 | php_file.close() 185 | 186 | 187 | def process_try(py_script): 188 | php_file = fileinput.FileInput(py_script, inplace=True) 189 | for line in php_file: 190 | reg = r'(.*)try(.*)\{$' 191 | match = re.match(reg, line) 192 | if match: 193 | groups = match.groups() 194 | try_indent = groups[0] 195 | try_line = try_indent + 'try:\n' 196 | sys.stdout.write(try_line) 197 | else: 198 | sys.stdout.write(line) 199 | 200 | php_file.close() 201 | 202 | 203 | def process_catch(py_script): 204 | php_file = fileinput.FileInput(py_script, inplace=True) 205 | for line in php_file: 206 | reg = r'(.*)}(.*)catch(.*)\((.*) +(.*)\)(.*)\{$' 207 | match = re.match(reg, line) 208 | if match: 209 | groups = match.groups() 210 | catch_indent = groups[0] 211 | catch_line = catch_indent + 'except ' + groups[3] + ' as ' + groups[4] + ':\n' 212 | sys.stdout.write(catch_line) 213 | else: 214 | sys.stdout.write(line) 215 | 216 | php_file.close() 217 | 218 | 219 | def convert2python(php_script, py_script, overwrite): 220 | if not os.path.exists(php_script): 221 | logger.error("Could not locate PHP script: %s" % php_script) 222 | return 223 | 224 | if os.path.exists(py_script): 225 | if not overwrite: 226 | logger.error("Sorry, A python Script %s already exist, use -o to overwrite." % py_script) 227 | return 228 | 229 | logger.info("Converting: %s. Output file will be: %s" % (php_script, py_script)) 230 | shutil.copyfile(php_script, py_script) 231 | 232 | logger.info('# Remove opening and closing to self.') 236 | replace(py_script, '$this->', 'self.') 237 | 238 | logger.info('# convert :: to .') 239 | replace(py_script, '::', '.') 240 | 241 | logger.info('# Process if statements') 242 | process_if(py_script) 243 | 244 | logger.info('# Process else statements') 245 | process_else(py_script) 246 | 247 | logger.info('# Process try statements') 248 | process_try(py_script) 249 | 250 | logger.info('# Process catch statements') 251 | process_catch(py_script) 252 | 253 | logger.info('# delete all }') 254 | logger.info('# delete namespace|require_once|include_once') 255 | remove_lines_bound(py_script, "namespace", ";") 256 | remove_lines_bound(py_script, "require_once", ";") 257 | remove_lines_bound(py_script, "include_once", ";") 258 | remove_lines_bound(py_script, "\{", "") 259 | remove_lines_bound(py_script, "\}", "") 260 | 261 | logger.info('# convert protected $var to self.var = None then move into __init__') 262 | logger.info('# convert public|protected function to def') 263 | logger.info('# add `self` to function signatures') 264 | add_self_to_functions(py_script) 265 | 266 | logger.info('# classes not children to extend `object`') 267 | logger.info('# process child classes') 268 | class_definition(py_script) 269 | 270 | logger.info('# convert $ to \'\'') 271 | replace(py_script, '$', '') 272 | 273 | logger.info('# convert ; to \'\'') 274 | replace(py_script, ';', '') 275 | 276 | logger.info('# convert new to \'\'') 277 | replace(py_script, 'new ', '') 278 | 279 | logger.info('# process foreach') 280 | process_foreach(py_script) 281 | 282 | logger.info(("Converted: %s. to: %s. { Go on, Proof Check :) }" % (php_script, py_script))) 283 | 284 | 285 | def main(): 286 | parser = argparse.ArgumentParser(description='PHP to PYTHON syntax converter.') 287 | parser.add_argument('-s', '--script', help='Path to PHP script', required=True) 288 | parser.add_argument('-o', '--overwrite', help='Overwrite Python script if exists', action='store_true') 289 | 290 | args = parser.parse_args() 291 | php_script = args.script 292 | py_script = python_script_name(php_script) 293 | 294 | convert2python(php_script, py_script, args.overwrite) 295 | 296 | 297 | if __name__ == '__main__': 298 | main() 299 | --------------------------------------------------------------------------------