Subversion Repositories fastphp

Rev

Rev 83 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 83 Rev 91
1
unit FastPHPUtils;
1
unit FastPHPUtils;
2
 
2
 
3
interface
3
interface
4
 
4
 
5
uses
5
uses
6
  Windows, SysUtils, StrUtils, Dialogs, IniFiles, Classes, Forms, ShellAPI, Functions,
6
  Windows, SysUtils, StrUtils, Dialogs, IniFiles, Classes, Forms, ShellAPI, Functions,
7
  System.UITypes;
7
  System.UITypes;
8
 
8
 
9
const
9
const
10
  FASTPHP_GOTO_URI_PREFIX = 'fastphp://editor/gotoline/';
10
  FASTPHP_GOTO_URI_PREFIX = 'fastphp://editor/gotoline/';
11
 
11
 
12
function GetPHPExe: string;
12
function GetPHPExe: string;
13
function RunPHPScript(APHPFileName: string; lint: boolean=false; inConsole: boolean=False; ContentCallBack: TContentCallBack=nil): string;
13
function RunPHPScript(APHPFileName: string; lint: boolean=false; inConsole: boolean=False; ContentCallBack: TContentCallBack=nil): string;
14
function ParseCHM(const chmFile: TFileName): boolean;
14
function ParseCHM(const chmFile: TFileName): boolean;
15
function IsValidPHPExe(const exeFile: TFileName): boolean;
15
function IsValidPHPExe(const exeFile: TFileName): boolean;
16
 
16
 
17
implementation
17
implementation
18
 
18
 
19
uses
19
uses
20
  FastPHPConfig;
20
  FastPHPConfig;
21
 
21
 
22
function GetPHPExe: string;
22
function GetPHPExe: string;
23
var
23
var
24
  od: TOpenDialog;
24
  od: TOpenDialog;
25
begin
25
begin
26
  result := TFastPHPConfig.PhpInterpreter;
26
  result := TFastPHPConfig.PhpInterpreter;
27
  if not FileExists(result) then
27
  if not FileExists(result) then
28
  begin
28
  begin
29
    od := TOpenDialog.Create(nil);
29
    od := TOpenDialog.Create(nil);
30
    try
30
    try
31
      od.DefaultExt := '.exe';
31
      od.DefaultExt := '.exe';
32
      od.FileName := 'php.exe';
32
      od.FileName := 'php.exe';
33
      od.Filter := 'Executable file (*.exe)|*.exe';
33
      od.Filter := 'Executable file (*.exe)|*.exe';
34
      od.Options := [ofReadOnly, ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing];
34
      od.Options := [ofReadOnly, ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing];
35
      od.Title := 'Please choose your PHP interpreter (php.exe)';
35
      od.Title := 'Please choose your PHP interpreter (php.exe)';
36
 
36
 
37
      if not od.Execute then exit;
37
      if not od.Execute then exit;
38
      if not FileExists(od.FileName) then exit;
38
      if not FileExists(od.FileName) then exit;
39
      result := od.FileName;
39
      result := od.FileName;
40
    finally
40
    finally
41
      od.Free;
41
      od.Free;
42
    end;
42
    end;
43
 
43
 
44
    if not IsValidPHPExe(result) then
44
    if not IsValidPHPExe(result) then
45
    begin
45
    begin
46
      MessageDlg('This is not a valid PHP executable.', mtError, [mbOk], 0);
46
      MessageDlg('This is not a valid PHP executable.', mtError, [mbOk], 0);
47
      exit;
47
      exit;
48
    end;
48
    end;
49
 
49
 
50
    TFastPHPConfig.PhpInterpreter := result;
50
    TFastPHPConfig.PhpInterpreter := result;
51
  end;
51
  end;
52
end;
52
end;
53
 
53
 
54
function RunPHPScript(APHPFileName: string; lint: boolean=false; inConsole: boolean=False; ContentCallBack: TContentCallBack=nil): string;
54
function RunPHPScript(APHPFileName: string; lint: boolean=false; inConsole: boolean=False; ContentCallBack: TContentCallBack=nil): string;
55
var
55
var
56
  phpExe, args, batFile, workdir: string;
56
  phpExe, args, batFile, workdir: string;
57
  slBat: TStringList;
57
  slBat: TStringList;
58
begin
58
begin
59
  phpExe := GetPHPExe;
59
  phpExe := GetPHPExe;
60
  if phpExe = '' then Abort;
60
  if phpExe = '' then Abort;
61
 
61
 
62
  if lint then
62
  if lint then
63
    args := '-l "'+APHPFileName+'"'
63
    args := '-l "'+APHPFileName+'"'
64
  else
64
  else
65
    args := '-f "'+APHPFileName+'"';
65
    args := '-f "'+APHPFileName+'"';
66
 
66
 
67
  //workdir := ExtractFileDir(ParamStr(0));
67
  //workdir := ExtractFileDir(ParamStr(0));
68
  workdir := ExtractFileDir(APHPFileName);
68
  workdir := ExtractFileDir(APHPFileName);
69
 
69
 
70
  if inConsole then
70
  if inConsole then
71
  begin
71
  begin
72
    (*
72
    (*
73
    ShellExecute(0, 'open', PChar(phpExe), PChar(args), PChar(workdir), SW_NORMAL);
73
    ShellExecute(0, 'open', PChar(phpExe), PChar(args), PChar(workdir), SW_NORMAL);
74
    *)
74
    *)
75
    batFile := IncludeTrailingPathDelimiter(GetTempDir) + 'RunFastPHP.bat';
75
    batFile := IncludeTrailingPathDelimiter(GetTempDir) + 'RunFastPHP.bat';
76
    slBat := TStringList.Create;
76
    slBat := TStringList.Create;
77
    try
77
    try
78
      slBat.Add('@echo off');
78
      slBat.Add('@echo off');
79
      slBat.Add('cd /d "'+workdir+'"');
79
      slBat.Add('cd /d "'+workdir+'"');
80
      slBat.Add('"'+phpExe+'" ' + args);
80
      slBat.Add('"'+phpExe+'" ' + args);
81
      slBat.Add('pause.');
81
      slBat.Add('pause.');
82
      slBat.SaveToFile(batFile);
82
      slBat.SaveToFile(batFile);
83
      ShellExecute(0, 'open', PChar(batFile), '', '', SW_NORMAL);
83
      ShellExecute(0, 'open', PChar(batFile), '', '', SW_NORMAL);
84
    finally
84
    finally
85
      slBat.Free;
85
      slBat.Free;
86
    end;
86
    end;
87
 
87
 
88
    result := '';
88
    result := '';
89
  end
89
  end
90
  else
90
  else
91
  begin
91
  begin
92
    result := GetDosOutput('"'+phpExe+'" ' + args, workdir, ContentCallBack);
92
    result := GetDosOutput('"'+phpExe+'" ' + args, workdir, ContentCallBack);
93
  end;
93
  end;
94
end;
94
end;
95
 
95
 
96
function ParseCHM(const chmFile: TFileName): boolean;
96
function ParseCHM(const chmFile: TFileName): boolean;
97
var
97
var
98
  test, candidate, candidate2: string;
98
  test, candidate, candidate2: string;
99
  p, p2, q: integer;
99
  p, p2, q: integer;
100
  i: integer;
100
  i: integer;
101
  good: Boolean;
101
  good: Boolean;
102
  ini: TMemIniFile;
102
  ini: TMemIniFile;
103
  domain: string;
103
  domain: string;
104
  sl: TStringList;
104
  sl: TStringList;
105
  symbolCount: Integer;
105
  symbolCount: Integer;
106
  sl2: TStrings;
106
  sl2: TStrings;
107
  outFile: string;
107
  outFile: string;
108
begin
108
begin
109
  // TODO: problem:  mysqli::commit has /res/mysqli.commit.html -> keyword is NOT commit alone
109
  // TODO: problem:  mysqli::commit has /res/mysqli.commit.html -> keyword is NOT commit alone
110
 
110
 
111
  outFile := ChangeFileExt(chmFile, '.ini');
111
  outFile := ChangeFileExt(chmFile, '.ini');
112
  DeleteFile(outFile);
112
  DeleteFile(outFile);
113
  test := LoadFileToStr(chmFile);
113
  test := LoadFileToStr(chmFile); // TODO: RawByteString instead of AnsiString?
114
  if Pos('/php_manual_', test) = -1 then
114
  if Pos('/php_manual_', test) = -1 then
115
  begin
115
  begin
116
    result := false;
116
    result := false;
117
    exit;
117
    exit;
118
  end;
118
  end;
119
  p := 0;
119
  p := 0;
120
  ini := TMemIniFile.Create(outFile);
120
  ini := TMemIniFile.Create(outFile);
121
  try
121
  try
122
    ini.WriteString('_Info_', 'Source', chmFile);
122
    ini.WriteString('_Info_', 'Source', chmFile);
123
    ini.WriteString('_Info_', 'Generated', DateTimeToStr(Now));
123
    ini.WriteString('_Info_', 'Generated', DateTimeToStr(Now));
124
    ini.WriteString('_Info_', 'GeneratorVer', '1.0');
124
    ini.WriteString('_Info_', 'GeneratorVer', '1.0');
125
    ini.WriteString('_Info_', 'Signature', '$ViaThinkSoft$');
125
    ini.WriteString('_Info_', 'Signature', '$ViaThinkSoft$');
126
    {$REGION 'Excludes'}
126
    {$REGION 'Excludes'}
127
    // TODO: more excludes
127
    // TODO: more excludes
128
    ini.WriteBool('_HelpExclude_', 'about', true);
128
    ini.WriteBool('_HelpExclude_', 'about', true);
129
    ini.WriteBool('_HelpExclude_', 'apache', true);
129
    ini.WriteBool('_HelpExclude_', 'apache', true);
130
    {$ENDREGION}
130
    {$ENDREGION}
131
    while true do
131
    while true do
132
    begin
132
    begin
133
      if Assigned(Application) then Application.ProcessMessages;
133
      if Assigned(Application) then Application.ProcessMessages;
134
 
134
 
135
      p := PosEx('/res/', Test, p+1);
135
      p := PosEx('/res/', Test, p+1);
136
      if p = 0 then break;
136
      if p = 0 then break;
137
      p2 := PosEx('.html', Test, p);
137
      p2 := PosEx('.html', Test, p);
138
      if p = 0 then break;
138
      if p = 0 then break;
139
      candidate := copy(Test, p+5, p2-p-5);
139
      candidate := copy(Test, p+5, p2-p-5);
140
      if candidate = '' then continue;
140
      if candidate = '' then continue;
141
      if Length(candidate) > 50 then continue;
141
      if Length(candidate) > 50 then continue;
142
      good := true;
142
      good := true;
143
      for i := p+5 to p2-1 do
143
      for i := p+5 to p2-1 do
144
      begin
144
      begin
145
        if ord(test[i]) < 32 then
145
        if ord(test[i]) < 32 then
146
        begin
146
        begin
147
          good := false;
147
          good := false;
148
          break;
148
          break;
149
        end;
149
        end;
150
        {$IFDEF UNICODE}
150
        {$IFDEF UNICODE}
151
        if not CharInSet(test[i], ['a'..'z', 'A'..'Z', '.', '-', '_', '0'..'9']) then
151
        if not CharInSet(test[i], ['a'..'z', 'A'..'Z', '.', '-', '_', '0'..'9']) then
152
        {$ELSE}
152
        {$ELSE}
153
        if not (test[i] in ['a'..'z', 'A'..'Z', '.', '-', '_', '0'..'9']) then
153
        if not (test[i] in ['a'..'z', 'A'..'Z', '.', '-', '_', '0'..'9']) then
154
        {$ENDIF}
154
        {$ENDIF}
155
        begin
155
        begin
156
          ini.WriteInteger('_Errors_', 'Contains unexpected character! ' + candidate, ini.ReadInteger('_Errors_', 'Contains unexpected character! ' + candidate, 0)+1);
156
          ini.WriteInteger('_Errors_', 'Contains unexpected character! ' + candidate, ini.ReadInteger('_Errors_', 'Contains unexpected character! ' + candidate, 0)+1);
157
          good := false;
157
          good := false;
158
          break;
158
          break;
159
        end;
159
        end;
160
      end;
160
      end;
161
      if good then
161
      if good then
162
      begin
162
      begin
163
        candidate2 := LowerCase(StringReplace(candidate, '-', '_', [rfReplaceAll]));
163
        candidate2 := LowerCase(StringReplace(candidate, '-', '_', [rfReplaceAll]));
164
        q := LastPos('.', candidate2);
164
        q := LastPos('.', candidate2);
165
        domain := copy(candidate2, 1, q-1);
165
        domain := copy(candidate2, 1, q-1);
166
        if domain = '' then continue;
166
        if domain = '' then continue;
167
        candidate2 := copy(candidate2, q+1, Length(candidate2)-q);
167
        candidate2 := copy(candidate2, q+1, Length(candidate2)-q);
168
        ini.WriteInteger('_Category_', domain, ini.ReadInteger('_Category_', domain, 0)+1);
168
        ini.WriteInteger('_Category_', domain, ini.ReadInteger('_Category_', domain, 0)+1);
169
        ini.WriteString(domain, candidate2, '/res/'+candidate+'.html');
169
        ini.WriteString(domain, candidate2, '/res/'+candidate+'.html');
170
        if not ini.ReadBool('_HelpExclude_', domain, false)
170
        if not ini.ReadBool('_HelpExclude_', domain, false)
171
           and (candidate2 <> 'configuration')
171
           and (candidate2 <> 'configuration')
172
           and (candidate2 <> 'constants')
172
           and (candidate2 <> 'constants')
173
           and (candidate2 <> 'installation')
173
           and (candidate2 <> 'installation')
174
           and (candidate2 <> 'requirements')
174
           and (candidate2 <> 'requirements')
175
           and (candidate2 <> 'resources')
175
           and (candidate2 <> 'resources')
176
           and (candidate2 <> 'setup') then
176
           and (candidate2 <> 'setup') then
177
        begin
177
        begin
178
          if ini.ReadString('_HelpWords_', candidate2, '') <> '' then
178
          if ini.ReadString('_HelpWords_', candidate2, '') <> '' then
179
          begin
179
          begin
180
            ini.WriteInteger('_Conflicts_', candidate2, ini.ReadInteger('_Conflicts_', candidate2, 0)+1);
180
            ini.WriteInteger('_Conflicts_', candidate2, ini.ReadInteger('_Conflicts_', candidate2, 0)+1);
181
          end;
181
          end;
182
 
182
 
183
          ini.WriteString('_HelpWords_', candidate2, '/res/'+candidate+'.html');
183
          ini.WriteString('_HelpWords_', candidate2, '/res/'+candidate+'.html');
184
        end;
184
        end;
185
      end;
185
      end;
186
    end;
186
    end;
187
 
187
 
188
    sl := TStringList.Create;
188
    sl := TStringList.Create;
189
    sl2 := TStringList.Create;
189
    sl2 := TStringList.Create;
190
    try
190
    try
191
      ini.ReadSections(sl);
191
      ini.ReadSections(sl);
192
      ini.WriteInteger('_Info_', 'TotalDomains', sl.Count);
192
      ini.WriteInteger('_Info_', 'TotalDomains', sl.Count);
193
      symbolCount := 0;
193
      symbolCount := 0;
194
      for domain in sl do
194
      for domain in sl do
195
      begin
195
      begin
196
        ini.ReadSection(domain, sl2);
196
        ini.ReadSection(domain, sl2);
197
        Inc(symbolCount, sl2.Count)
197
        Inc(symbolCount, sl2.Count)
198
      end;
198
      end;
199
      ini.WriteInteger('_Info_', 'TotalSymbols', symbolCount);
199
      ini.WriteInteger('_Info_', 'TotalSymbols', symbolCount);
200
    finally
200
    finally
201
      sl.Free;
201
      sl.Free;
202
      sl2.Free;
202
      sl2.Free;
203
    end;
203
    end;
204
 
204
 
205
    ini.UpdateFile;
205
    ini.UpdateFile;
206
    result := true;
206
    result := true;
207
  finally
207
  finally
208
    ini.Free;
208
    ini.Free;
209
  end;
209
  end;
210
end;
210
end;
211
 
211
 
212
function IsValidPHPExe(const exeFile: TFileName): boolean;
212
function IsValidPHPExe(const exeFile: TFileName): boolean;
213
var
213
var
214
  cont: string;
214
  cont: string;
215
begin
215
begin
216
  cont := LoadFileToStr(exeFile);
216
  cont := LoadFileToStr(exeFile); // TODO: RawByteString instead of AnsiString?
217
  result := (Pos('php://stdout', cont) >= 0) or
217
  result := (Pos('php://stdout', cont) >= 0) or
218
            (Pos('PHP_SELF', cont) >= 0);
218
            (Pos('PHP_SELF', cont) >= 0);
219
end;
219
end;
220
 
220
 
221
end.
221
end.
222
 
222