由于您的问题是格式化现有代码体,因此您不需要 IDE。您需要一个脚本来批处理所有文件一次,然后您就可以忘记它。这是脚本需要做的:
- 正确解析PHP字符串,包括带有各种嵌入或转义引号的字符串。这应该是防弹的,并且应该只关心 PHP 语法。
- 使用检测 SQL 命令的算法检查每个 PHP 字符串。这可以根据您的需要变得聪明(例如,无需盲目地接受每个包含单词“insert”的字符串)。
- 通过 SQL 漂亮打印机提供已识别的字符串。
- 编辑输入文件,用格式化字符串替换原始文件。
理想情况下,第 1 部分和第 3 部分应由现成的模块处理。其余的应该很容易自己组装,对吧?
更新:解释这听起来很简单,我决定自己做。这是一个快速的解决方案。它在 python 中,但如果你愿意切换 IDE,你可以处理安装 python,对吗?
将任意数量的 php 文件拖放到脚本上,或从命令行调用它,它将通过@Parahat 建议的SQLFormat API过滤 SQL 位。它会在原地编辑文件,因此请保留一份副本!
"""Format sql strings embedded in php code, editing source IN PLACE"""
import sys, re, urllib, urllib2
def processfile(fname):
with open(fname) as fp:
text = fp.read()
with open(fname, "w") as out:
for token in chunk(text):
if is_sql_string(token):
token = token[0] + sqlformat(token[1:-1]) + token[0]
out.write(token)
def sqlformat(query):
sqlapi = 'http://sqlformat.appspot.com/format/?keyword_case=upper&reindent=1&n_indents=4&'
return urllib2.urlopen(sqlapi+urllib.urlencode({'data':query})).read()
php_mode = False # global, so that is_sql_string() can examine it
def chunk(src):
"""Chunk the php file into interesting units"""
global php_mode
while src:
if not php_mode: # Read up to the next php group, if any
m = re.match(r".*?<\?php", src, re.S)
if m:
tok, src = _usematch(m, src)
yield tok
php_mode = True
else: # No more php groups: EOF
yield src
return
else: # Reading php code
# PHP ends without another string?
m = re.match(r"[^'\"]*?\?>", src, re.S)
if m:
tok, src = _usematch(m, src)
yield tok
php_mode = False
continue
# at non-string material?
m = re.match(r"[^'\"]+", src)
if m:
tok, src = _usematch(m, src)
yield tok
continue
# Parse a string: Smallest quote-delimited sequence,
# where closing quote is not preceded by backslash
m = re.match(r'".*?(?<!\\)"|' + r"'.*?(?<!\\)'", src, re.S)
if m:
tok, src = _usematch(m, src)
yield tok
continue
# Something I can't parse: advance one char and hope for the best
tok, src = src[0], src[1:]
yield tok
def _usematch(m, inp):
return m.group(), inp[m.end():] # Matched chunk & remaining input
# To recognize an sql command, it MUST begin with one of these words
sql_commands = set("select insert update delete create drop alter declare".split())
def is_sql_string(tok):
if not php_mode or len(tok) < 3 or tok[0] not in set("\"'"):
return False
tokwords = tok[1:-1].split()
return tokwords and tokwords[0].lower() in sql_commands
for fname in sys.argv[1:]:
processfile(fname)