summaryrefslogtreecommitdiff
path: root/zend/file.cpp
blob: 98c14414d72483c74ae92c37b7e49a8594d0502c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
 *  File.cpp
 *
 *  Implementation file for the File class
 *
 *  @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
 *  @copyright 2014 Copernica BV
 */

/**
 *  Dependencies
 */
#include "includes.h"

/**
 *  Namespace
 */
namespace Php {

/**
 *  Constructor
 * 
 *  The constructor receives a filename as parameter. It uses the normal
 *  PHP include path resolve algorithms to find the location of the file. 
 * 
 *  @param  name        the filename
 *  @param  size        length of the filename
 */
File::File(const char *name, size_t size)
{
    // we need the tsrm_ls variable
    TSRMLS_FETCH();
    
    // resolve the path
    _path = zend_resolve_path(name, size TSRMLS_CC);
    
    // the resolve-path function sometimes returns the original pointer, we
    // do not want that because we may have to store the pathname in this object
    if (_path != name) return;
    
    // make a full copy of the pathname
    _path = estrndup(name, size);
}

/**
 *  Destructor
 */
File::~File()
{
    // clean up path name
    if (_path) efree(_path);
    
    // clean up opcodes
    if (_opcodes) delete _opcodes;
}

/**
 *  Execute the file
 *  @return Value
 */
Value File::execute() 
{
    // do we already have the opcodes?
    if (_opcodes) return _opcodes->execute();

    // skip if there is no valid path
    if (!_path) return nullptr;

    // we are going to open the file
    zend_file_handle fileHandle;

    // open the file
    if (zend_stream_open(_path, &fileHandle TSRMLS_CC) == FAILURE) return nullptr;

    // make sure the path name is stored in the handle
    if (!fileHandle.opened_path) fileHandle.opened_path = estrdup(_path);
    
    // we need temporary compiler options
    CompilerOptions options(ZEND_COMPILE_DEFAULT);
    
    // we need the tsrm_ls variable
    TSRMLS_FETCH();
    
    // create the opcodes
    _opcodes = new Opcodes(zend_compile_file(&fileHandle, ZEND_INCLUDE TSRMLS_CC));

    // close the file handle
    zend_destroy_file_handle(&fileHandle TSRMLS_CC);

    // add the entry to the list of included files
    zend_hash_add_empty_element(&EG(included_files), _path, ::strlen(_path) + 1);
    
    // execute the opcodes
    return _opcodes->execute();
}

/**
 *  Execute a file only once
 *  @return Value
 */
Value File::once() 
{
    // skip if the opcodes are already known (then we know for sure that the 
    // file was already executed), also leap out if the filename was not even valid
    if (_opcodes || !_path) return nullptr;
    
    // check if this file was already included
    if (zend_hash_exists(&EG(included_files), _path, ::strlen(_path) + 1)) return nullptr;

    // execute the file
    return execute();
}

/**
 *  End of namespace
 */
}