_getChildBlockNames()   A
last analyzed

Complexity

Conditions 5
Paths 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.2408
c 0
b 0
f 0
cc 5
nc 2
nop 1
1
<?php
2
3
/**
4
 * Nexcess.net Turpentine Extension for Magento
5
 * Copyright (C) 2012  Nexcess.net L.L.C.
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, write to the Free Software Foundation, Inc.,
19
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
 */
21
22
class Nexcessnet_Turpentine_Helper_Data extends Mage_Core_Helper_Abstract {
23
24
    /**
25
     * Contains a newly generated v4 uuid whenever read, possibly not available
26
     * on all kernels
27
     */
28
    const UUID_SOURCE = '/proc/sys/kernel/random/uuid';
29
30
    /**
31
     * Compression level for serialization compression
32
     *
33
     * Testing showed no significant (size) difference between levels 1 and 9
34
     * so using 1 since it's faster
35
     */
36
    const COMPRESSION_LEVEL = 1;
37
38
    /**
39
     * Hash algorithm to use in various cryptographic methods
40
     */
41
    const HASH_ALGORITHM = 'sha256';
42
43
    /**
44
     * Cookie name for the Varnish bypass
45
     *
46
     * @var string
47
     */
48
    const BYPASS_COOKIE_NAME = 'varnish_bypass';
49
50
    /**
51
     * encryption singleton thing
52
     *
53
     * @var Mage_Core_Model_Encryption
54
     */
55
    protected $_crypt = null;
56
57
    /**
58
     * Like built-in explode() but applies trim to each exploded element and
59
     * filters out empty elements from result
60
     *
61
     * @param  string $token [description]
62
     * @param  string $data  [description]
63
     * @return array
64
     */
65
    public function cleanExplode($token, $data) {
66
        return array_filter(array_map('trim',
67
            explode($token, trim($data))));
68
    }
69
70
    /**
71
     * Generate a v4 UUID
72
     *
73
     * @return string
74
     */
75
    public function generateUuid() {
76
        if (is_readable(self::UUID_SOURCE)) {
77
            $uuid = trim(file_get_contents(self::UUID_SOURCE));
78
        } elseif (function_exists('mt_rand')) {
79
            /**
80
             * Taken from stackoverflow answer, possibly not the fastest or
81
             * strictly standards compliant
82
             * @link http://stackoverflow.com/a/2040279
83
             */
84
            $uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
85
                // 32 bits for "time_low"
86
                mt_rand(0, 0xffff), mt_rand(0, 0xffff),
87
88
                // 16 bits for "time_mid"
89
                mt_rand(0, 0xffff),
90
91
                // 16 bits for "time_hi_and_version",
92
                // four most significant bits holds version number 4
93
                mt_rand(0, 0x0fff) | 0x4000,
94
95
                // 16 bits, 8 bits for "clk_seq_hi_res",
96
                // 8 bits for "clk_seq_low",
97
                // two most significant bits holds zero and one for variant DCE1.1
98
                mt_rand(0, 0x3fff) | 0x8000,
99
100
                // 48 bits for "node"
101
                mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
102
            );
103
        } else {
104
            // chosen by dice roll, guaranteed to be random
105
            $uuid = '4';
106
        }
107
        return $uuid;
108
    }
109
110
    /**
111
     * Get the Turpentine version
112
     *
113
     * @return string
114
     */
115
    public function getVersion() {
116
        return Mage::getConfig()
117
            ->getModuleConfig('Nexcessnet_Turpentine')->version;
118
    }
119
120
    /**
121
     * Base64 encode a string
122
     *
123
     * NOTE this changes the last 2 characters to be friendly to URLs
124
     *     / => .
125
     *     + => -
126
     *
127
     * @param  string $str
128
     * @return string
129
     */
130
    public function urlBase64Encode($str) {
131
        return str_replace(
132
            array('/', '+'),
133
            array('_', '-'),
134
            base64_encode($str) );
135
    }
136
137
    /**
138
     * Base64 decode a string, counterpart to urlBase64Encode
139
     *
140
     * @param  string $str
141
     * @return string
142
     */
143
    public function urlBase64Decode($str) {
144
        return base64_decode(
145
            str_replace(
146
                array('_', '-'),
147
                array('/', '+'),
148
                $str ) );
149
    }
150
151
    /**
152
     * Serialize a variable into a string that can be used in a URL
153
     *
154
     * Using gzdeflate to avoid the checksum/metadata overhead in gzencode and
155
     * gzcompress
156
     *
157
     * @param  mixed $data
158
     * @return string
159
     */
160
    public function freeze($data) {
161
        Varien_Profiler::start('turpentine::helper::data::freeze');
162
        $frozenData = $this->urlBase64Encode(
163
            $this->_getCrypt()->encrypt(
164
                gzdeflate(
165
                    serialize($data),
166
                    self::COMPRESSION_LEVEL ) ) );
167
        Varien_Profiler::stop('turpentine::helper::data::freeze');
168
        return $frozenData;
169
    }
170
171
    /**
172
     * Unserialize data
173
     *
174
     * @param  string $data
175
     * @return mixed
176
     */
177
    public function thaw($data) {
178
        Varien_Profiler::start('turpentine::helper::data::thaw');
179
        $thawedData = unserialize(
180
            gzinflate(
181
                $this->_getCrypt()->decrypt(
182
                    $this->urlBase64Decode($data) ) ) );
183
        Varien_Profiler::stop('turpentine::helper::data::thaw');
184
        return $thawedData;
185
    }
186
187
    /**
188
     * Get SHA256 hash of a string, salted with encryption key
189
     *
190
     * @param  string $data
191
     * @return string
192
     */
193
    public function secureHash($data) {
194
        $salt = $this->_getCryptKey();
195
        return hash(self::HASH_ALGORITHM, sprintf('%s:%s', $salt, $data));
196
    }
197
198
    /**
199
     * Get the HMAC hash for given data
200
     *
201
     * @param  string $data
202
     * @return string
203
     */
204
    public function getHmac($data) {
205
        return hash_hmac(self::HASH_ALGORITHM, $data, $this->_getCryptKey());
206
    }
207
208
    /**
209
     * Hash a cache key the same way blocks do
210
     *
211
     * @param  array $key
212
     * @return string
213
     */
214
    public function getCacheKeyHash($key) {
215
        return sha1(implode('|', array_values($key)));
216
    }
217
218
    /**
219
     * Get a list of child blocks inside the given block
220
     *
221
     * @param  Mage_Core_Model_Layout_Element $blockNode
222
     * @return array
223
     */
224
    public function getChildBlockNames($blockNode) {
225
        return array_unique($this->_getChildBlockNames($blockNode));
226
    }
227
228
    /**
229
     * Get the getModel formatted name of a model classname or object
230
     *
231
     * @param  string|object $model
232
     * @return string
233
     */
234
    public function getModelName($model) {
235
        if (is_object($model)) {
236
            $model = get_class($model);
237
        }
238
        // This guess may work if the extension uses its lowercased name as model group name.
239
        $result = strtolower(preg_replace(
240
            '~^[^_]+_([^_]+)_Model_(.+)$~', '$1/$2', $model ));
241
        // This check is not expensive because the answer should come from Magento's classNameCache
242
        $checkModel = Mage::getConfig()->getModelClassName($result);
243
        if ('Mage_' == substr($checkModel, 0, 5) && ! class_exists($result)) {
244
            // Fallback to full model name.
245
            $result = $model;
246
        }
247
        return $result;
248
    }
249
250
    /**
251
     * Check config to see if Turpentine should handle the flash messages
252
     *
253
     * @return bool
254
     */
255
    public function useFlashMessagesFix() {
256
        return (bool) Mage::getStoreConfig(
257
            'turpentine_varnish/general/ajax_messages' );
258
    }
259
260
    /**
261
     * Check config to see if Turpentine should apply the product list toolbar
262
     * fix
263
     *
264
     * @return bool
265
     */
266
    public function useProductListToolbarFix() {
267
        return (bool) Mage::getStoreConfig(
268
            'turpentine_varnish/general/fix_product_toolbar' );
269
    }
270
271
    /**
272
     * Check if Turpentine should apply the new VCL on config changes
273
     *
274
     * @return bool
275
     */
276
    public function getAutoApplyOnSave() {
277
        return (bool) Mage::getStoreConfig(
278
            'turpentine_varnish/general/auto_apply_on_save' );
279
    }
280
281
    /**
282
     * Get config value specifying when to strip VCL whitespaces
283
     *
284
     * @return string
285
     */
286
    public function getVclFix() {
287
        return Mage::getStoreConfig(
288
            'turpentine_varnish/general/vcl_fix' );
289
    }
290
291
    /**
292
     * Get config value specifying when to strip VCL whitespaces
293
     *
294
     * @return string
295
     */
296
    public function getStripVclWhitespace() {
297
        return Mage::getStoreConfig(
298
            'turpentine_varnish/general/strip_vcl_whitespace' );
299
    }
300
301
    /**
302
     * Check if VCL whitespaces should be stripped for the given action
303
     *
304
     * @param string $action can be either "apply", "save" or "download"
305
     * @return bool
306
     */
307
    public function shouldStripVclWhitespace($action) {
308
        $configValue = $this->getStripVclWhitespace();
309
        if ($configValue === 'always') {
310
            return true;
311
        } elseif ($configValue === 'apply' && $action === 'apply') {
312
            return true;
313
        }
314
        return false;
315
    }
316
317
    /**
318
     * Get the cookie name for the Varnish bypass
319
     *
320
     * @return string
321
     */
322
    public function getBypassCookieName() {
323
        return self::BYPASS_COOKIE_NAME;
324
    }
325
326
    /**
327
     * The actual recursive implementation of getChildBlockNames
328
     *
329
     * @param  Mage_Core_Model_Layout_Element $blockNode
330
     * @return array
331
     */
332
    protected function _getChildBlockNames($blockNode) {
333
        Varien_Profiler::start('turpentine::helper::data::_getChildBlockNames');
334
        if ($blockNode instanceof Mage_Core_Model_Layout_Element) {
0 ignored issues
show
Bug introduced by
The class Mage_Core_Model_Layout_Element does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
335
            $blockNames = array((string) $blockNode['name']);
336
            foreach ($blockNode->xpath('./block | ./reference') as $childBlockNode) {
337
                $blockNames = array_merge($blockNames,
338
                    $this->_getChildBlockNames($childBlockNode));
339
                if ($this->getLayout() instanceof Varien_Simplexml_Config) {
0 ignored issues
show
Bug introduced by
The class Varien_Simplexml_Config does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
340
                    foreach ($this->getLayout()->getNode()->xpath(sprintf(
341
                        '//reference[@name=\'%s\']', (string) $childBlockNode['name'] ))
342
                            as $childBlockLayoutNode) {
343
                        $blockNames = array_merge($blockNames,
344
                            $this->_getChildBlockNames($childBlockLayoutNode));
345
346
                    }
347
                }
348
            }
349
        } else {
350
            $blockNames = array();
351
        }
352
        Varien_Profiler::stop('turpentine::helper::data::_getChildBlockNames');
353
        return $blockNames;
354
    }
355
356
    /**
357
     * Get encryption singleton thing
358
     *
359
     * Not using core/cryption because it auto-base64 encodes stuff which we
360
     * don't want in this case
361
     *
362
     * @return Mage_Core_Model_Encryption
363
     */
364
    protected function _getCrypt() {
365
        if (is_null($this->_crypt)) {
366
            $this->_crypt = Varien_Crypt::factory()
367
                ->init($this->_getCryptKey());
368
        }
369
        return $this->_crypt;
370
    }
371
372
    /**
373
     * Get Magento's encryption key
374
     *
375
     * @return string
376
     */
377
    protected function _getCryptKey() {
378
        return (string) Mage::getConfig()->getNode('global/crypt/key');
379
    }
380
}
381