1+ <?php
2+
3+ class XDebugParser
4+ {
5+
6+ protected $ handle ;
7+
8+ protected $ functions = array ();
9+
10+ public function __construct ($ fileName )
11+ {
12+ $ this ->handle = fopen ($ fileName , 'r ' );
13+ if (!$ this ->handle ) {
14+ throw new Exception ("Can't open ' $ fileName' " );
15+ }
16+ $ header1 = fgets ($ this ->handle );
17+ $ header2 = fgets ($ this ->handle );
18+ if (!preg_match ('@Version: [23].*@ ' , $ header1 ) || !preg_match ('@File format: [2-4]@ ' , $ header2 )) {
19+ throw new Exception ("This file is not an Xdebug trace file made with format option '1' and version 2 to 4. " );
20+ }
21+ }
22+
23+ public function parse ()
24+ {
25+ $ c = 0 ;
26+ $ size = fstat ($ this ->handle );
27+ $ size = $ size ['size ' ];
28+ $ read = 0 ;
29+
30+ while (!feof ($ this ->handle )) {
31+ $ buffer = fgets ($ this ->handle , 4096 );
32+ $ read += strlen ($ buffer );
33+ $ this ->parseLine ($ buffer );
34+ $ c ++;
35+ }
36+ }
37+
38+ function parseLine ($ line )
39+ {
40+ $ parts = explode ("\t" , $ line );
41+ if (count ($ parts ) < 5 ) {
42+ return ;
43+ }
44+
45+ $ funcNr = (int ) $ parts [1 ];
46+ $ type = $ parts [2 ];
47+
48+ switch ($ type ) {
49+ case '0 ' : // Function enter
50+ $ this ->functions [$ funcNr ] = array ();
51+ $ this ->functions [$ funcNr ]['depth ' ] = (int ) $ parts [0 ];
52+ $ this ->functions [$ funcNr ]['time.enter ' ] = $ parts [3 ];
53+ $ this ->functions [$ funcNr ]['memory.enter ' ] = $ parts [4 ];
54+ $ this ->functions [$ funcNr ]['name ' ] = $ parts [5 ];
55+ $ this ->functions [$ funcNr ]['internal ' ] = !(bool ) $ parts [6 ];
56+ $ this ->functions [$ funcNr ]['file ' ] = $ parts [8 ];
57+ $ this ->functions [$ funcNr ]['line ' ] = $ parts [9 ];
58+ if ($ parts [7 ]) {
59+ $ this ->functions [$ funcNr ]['params ' ] = array ($ parts [7 ]);
60+ } else {
61+ $ this ->functions [$ funcNr ]['params ' ] = array_slice ($ parts , 11 );
62+ }
63+
64+ // these are set later
65+ $ this ->functions [$ funcNr ]['time.exit ' ] = '' ;
66+ $ this ->functions [$ funcNr ]['memory.exit ' ] = '' ;
67+ $ this ->functions [$ funcNr ]['time.diff ' ] = '' ;
68+ $ this ->functions [$ funcNr ]['memory.diff ' ] = '' ;
69+ $ this ->functions [$ funcNr ]['return ' ] = '' ;
70+ break ;
71+ case '1 ' : // Function exit
72+ $ this ->functions [$ funcNr ]['time.exit ' ] = $ parts [3 ];
73+ $ this ->functions [$ funcNr ]['memory.exit ' ] = $ parts [4 ];
74+ $ this ->functions [$ funcNr ]['time.diff ' ] = $ this ->functions [$ funcNr ]['time.exit ' ] - $ this ->functions [$ funcNr ]['time.enter ' ];
75+ $ this ->functions [$ funcNr ]['memory.diff ' ] = $ this ->functions [$ funcNr ]['memory.exit ' ] - $ this ->functions [$ funcNr ]['memory.enter ' ];
76+ break ;
77+ case 'R ' ; // Function return
78+ $ this ->functions [$ funcNr ]['return ' ] = $ parts [5 ];
79+ break ;
80+ }
81+ }
82+
83+ function getTrace ()
84+ {
85+ return $ this ->functions ;
86+ }
87+
88+ function getTraceHTML ()
89+ {
90+ ob_start ();
91+
92+ echo '<div class="f header"> ' ;
93+ echo '<div class="func">Function Call</div> ' ;
94+ echo '<div class="data"> ' ;
95+ echo '<span class="timediff">ΔTime</span> ' ;
96+ echo '<span class="memorydiff">ΔMemory</span> ' ;
97+ echo '<span class="time">Time</span> ' ;
98+ echo '</div> ' ;
99+ echo '</div> ' ;
100+
101+
102+ $ level = 0 ;
103+ foreach ($ this ->functions as $ func ) {
104+ // depth wrapper
105+ if ($ func ['depth ' ] > $ level ) {
106+ for ($ i = $ level ; $ i < $ func ['depth ' ]; $ i ++) {
107+ echo '<div class="d"> ' ;
108+ }
109+ } elseif ($ func ['depth ' ] < $ level ) {
110+ for ($ i = $ func ['depth ' ]; $ i < $ level ; $ i ++) {
111+ echo '</div> ' ;
112+ }
113+ }
114+ $ level = $ func ['depth ' ];
115+
116+ $ class = 'f ' ;
117+ if ($ func ['internal ' ]) {
118+ $ class .= ' i ' ;
119+ }
120+
121+ echo '<div class=" ' . $ class . '"> ' ;
122+
123+ echo '<div class="func"> ' ;
124+ echo '<span class="name"> ' . htmlspecialchars ($ func ['name ' ]) . '</span> ' ;
125+ echo '(<span class="params short"> ' . htmlspecialchars (join (", " , $ func ['params ' ])) . '</span>) ' ;
126+ if ($ func ['return ' ] !== '' ) {
127+ echo '→ <span class="return short"> ' . htmlspecialchars ($ func ['return ' ]) . '</span> ' ;
128+ }
129+ echo '</div> ' ;
130+
131+ echo '<div class="data"> ' ;
132+ echo '<span class="timediff"> ' . sprintf ('%f ' , $ func ['time.diff ' ]) . '</span> ' ;
133+ echo '<span class="memorydiff"> ' . sprintf ('%d ' , $ func ['memory.diff ' ]) . '</span> ' ;
134+ echo '<span class="time"> ' . sprintf ('%f ' , $ func ['time.enter ' ]) . '</span> ' ;
135+ echo '</div> ' ;
136+
137+ echo '</div> ' ;
138+ }
139+
140+ $ html = ob_get_contents ();
141+ ob_end_clean ();
142+ return $ html ;
143+ }
144+
145+ }
0 commit comments