Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1047607
template_helper.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Jun 30, 4:27 AM
Size
12 KB
Mime Type
text/x-php
Expires
Wed, Jul 2, 4:27 AM (11 h, 56 m)
Engine
blob
Format
Raw Data
Handle
677410
Attached To
rINP In-Portal
template_helper.php
View Options
<?php
/**
* @version $Id: template_helper.php 11963 2009-07-22 15:13:17Z alex $
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
class
TemplateHelper
extends
kHelper
{
/**
* parser element location information
*
* @var Array
*/
var
$_blockLocation
=
Array
();
/**
* Block name, that will be used
*
* @var string
*/
var
$_blockName
=
''
;
/**
* Function name, that represents compiled block
*
* @var sting
*/
var
$_functionName
=
''
;
/**
* Errors found during template parsing
*
* @var Array
*/
var
$_parseErrors
=
Array
();
/**
* Source template, that is being edited
*
* @var string
*/
var
$_sourceTemplate
=
''
;
var
$_initMade
=
false
;
/**
* Performs init ot helper
*
* @param kDBItem $object
*/
function
InitHelper
(&
$object
)
{
if
(
$this
->
_initMade
)
{
return
;
}
define
(
'DBG_IGNORE_FATAL_ERRORS'
,
1
);
// 1. get block information
$block_info
=
$this
->
Application
->
GetVar
(
'block'
);
list
(
$this
->
_blockName
,
$this
->
_functionName
)
=
explode
(
':'
,
$block_info
);
$this
->
_parseTemplate
(
$object
);
if
(
array_key_exists
(
$this
->
_functionName
,
$this
->
Application
->
Parser
->
ElementLocations
))
{
$this
->
_blockLocation
=
$this
->
Application
->
Parser
->
ElementLocations
[
$this
->
_functionName
];
}
$this
->
_initMade
=
true
;
}
function
_getSourceTemplate
()
{
// get source template
$t
=
$this
->
Application
->
GetVar
(
'source'
);
if
(!
$this
->
Application
->
TemplatesCache
->
TemplateExists
(
$t
))
{
$cms_handler
=&
$this
->
Application
->
recallObject
(
'st_EventHandler'
);
/* @var $cms_handler StructureEventHandler */
$t
=
ltrim
(
$cms_handler
->
GetDesignTemplate
(
$t
),
'/'
);
}
$this
->
_sourceTemplate
=
$t
;
}
function
_getThemeName
()
{
$theme_id
=
(
int
)
$this
->
Application
->
GetVar
(
'theme_id'
);
$sql
=
'SELECT Name
FROM '
.
$this
->
Application
->
getUnitOption
(
'theme'
,
'TableName'
)
.
'
WHERE '
.
$this
->
Application
->
getUnitOption
(
'theme'
,
'IDField'
)
.
' = '
.
$theme_id
;
return
$this
->
Conn
->
GetOne
(
$sql
);
}
/**
* Render source template to get parse errors OR it's element locations
*
* @param kDBItem $object
* @param string $append
* @return bool
*/
function
_parseTemplate
(&
$object
,
$append
=
''
)
{
// 1. set internal error handler to catch all parsing errors
$error_handlers
=
$this
->
Application
->
errorHandlers
;
$this
->
Application
->
errorHandlers
=
Array
(
Array
(&
$this
,
'_saveError'
),
);
// 2. parse template
$this
->
Application
->
InitParser
(
$this
->
_getThemeName
()
);
// we have no parser when saving block content
$this
->
_getSourceTemplate
();
// design templates have leading "/" in the beginning
$this
->
Application
->
Parser
->
Run
(
$this
->
_sourceTemplate
.
$append
);
// 3. restore original error handler
$this
->
Application
->
errorHandlers
=
$error_handlers
;
if
(
$this
->
_parseErrors
)
{
if
(
$this
->
_isMainTemplate
())
{
// 3.1. delete temporary file, that was parsed
$filename
=
$this
->
_getTemplateFile
(
false
,
$append
.
'.tpl'
);
if
(!
unlink
(
$filename
))
{
$error_file
=
$this
->
_getTemplateFile
(
true
,
$append
.
'.tpl'
);
$object
->
SetError
(
'FileContents'
,
'template_delete_failed'
,
'+Failed to delete temporary template "<strong>'
.
$error_file
.
'</strong>"'
);
return
false
;
}
}
else
{
// 3.2. restore backup
if
(!
rename
(
$this
->
_getTemplateFile
(
false
,
'.tpl.bak'
),
$this
->
_getTemplateFile
(
false
)))
{
$error_file
=
$this
->
_getTemplateFile
(
true
);
$object
->
SetError
(
'FileContents'
,
'template_restore_failed'
,
'+Failed to restore template "<strong>'
.
$error_file
.
'</strong>" from backup.'
);
return
false
;
}
}
return
false
;
}
return
true
;
}
/**
* Move elements in template and save changes, when possible
*
* @param Array $target_order
* @return bool
*/
function
moveTemplateElements
(
$target_order
)
{
// 2. parse template
$this
->
Application
->
InitParser
();
// we have no parser when saving block content
$this
->
_getSourceTemplate
();
$filename
=
$this
->
Application
->
TemplatesCache
->
GetRealFilename
(
$this
->
_sourceTemplate
)
.
'.tpl'
;
if
(!
is_writable
(
$filename
))
{
// we can't save changes, don't bother calculating new template contents
return
false
;
}
$data
=
file_get_contents
(
$filename
);
$line_ending
=
strpos
(
$data
,
"
\r
"
)
!==
false
?
"
\r\n
"
:
"
\n
"
;
// 1. get location of movable areas
$mask
=
''
;
$start_pos
=
0
;
$elements
=
Array
();
$areas
=
$this
->
_getDivPairs
(
$data
,
'movable-area'
);
foreach
(
$areas
as
$area_index
=>
$area
)
{
// 1.1. get locations of all movable elements inside given area
$area_content
=
substr
(
$area
[
'data'
],
$area
[
'open_len'
],
-
$area
[
'close_len'
]);
$elements
=
array_merge
(
$elements
,
$this
->
_getDivPairs
(
$area_content
,
'movable-element'
,
$area_index
,
$area
[
'open_pos'
]
+
$area
[
'open_len'
]));
// 1.2. prepare mask to place movable elements into (don't include movable area div ifself)
$mask
.=
"
\t
"
.
substr
(
$data
,
$start_pos
,
$area
[
'open_pos'
]
+
$area
[
'open_len'
]
-
$start_pos
)
.
$line_ending
.
"
\t\t
"
.
'#AREA'
.
$area_index
.
'#'
.
$line_ending
;
$start_pos
=
$area
[
'close_pos'
]
-
$area
[
'close_len'
];
}
$mask
=
trim
(
$mask
.
"
\t
"
.
substr
(
$data
,
$area
[
'close_pos'
]
-
$area
[
'close_len'
]));
if
(!
$elements
)
{
// no elements found
return
false
;
}
foreach
(
$areas
as
$area_index
=>
$area
)
{
$area_content
=
''
;
$target_elements
=
$target_order
[
$area_index
];
foreach
(
$target_order
[
$area_index
]
as
$old_location
)
{
$area_content
.=
$elements
[
$old_location
][
'data'
]
.
$line_ending
.
"
\t\t
"
;
}
$mask
=
str_replace
(
'#AREA'
.
$area_index
.
'#'
,
trim
(
$area_content
),
$mask
);
}
$fp
=
fopen
(
$filename
,
'w'
);
fwrite
(
$fp
,
$mask
);
fclose
(
$fp
);
return
true
;
}
/**
* Extracts div pairs with given class from given text
*
* @param string $data
* @param string $class
* @param int $area
* @param int $offset
* @return Array
*/
function
_getDivPairs
(&
$data
,
$class
,
$area
=
null
,
$offset
=
0
)
{
preg_match_all
(
'/(<div[^>]*>)|(<
\/
div>)/s'
,
$data
,
$divs
,
PREG_SET_ORDER
+
PREG_OFFSET_CAPTURE
);
$skip_count
=
0
;
$pairs
=
Array
();
foreach
(
$divs
as
$div
)
{
if
(
strpos
(
$div
[
0
][
0
],
'/'
)
===
false
)
{
// opening div
if
(
strpos
(
$div
[
0
][
0
],
$class
)
!==
false
)
{
$pair
=
Array
(
'open_pos'
=>
$div
[
0
][
1
],
'open_len'
=>
strlen
(
$div
[
0
][
0
]));
$skip_count
=
0
;
}
else
{
$skip_count
++;
}
}
else
{
// closing div
if
(
$skip_count
==
0
)
{
$pair
[
'close_len'
]
=
strlen
(
$div
[
0
][
0
]);
$pair
[
'close_pos'
]
=
$div
[
0
][
1
]
+
$pair
[
'close_len'
];
$pair
[
'data'
]
=
substr
(
$data
,
$pair
[
'open_pos'
],
$pair
[
'close_pos'
]
-
$pair
[
'open_pos'
]);
if
(
isset
(
$area
))
{
$pair
[
'open_pos'
]
+=
$offset
;
$pair
[
'close_pos'
]
+=
$offset
;
// index indicates area
$pairs
[
'a'
.
$area
.
'e'
.
count
(
$pairs
)]
=
$pair
;
}
else
{
$pairs
[]
=
$pair
;
}
}
else
{
$skip_count
--;
}
}
}
return
$pairs
;
}
/**
* Returns information about parser element locations in template
*
* @param Array $params
* @return mixed
*/
function
blockInfo
(
$info_type
)
{
switch
(
$info_type
)
{
case
'block_name'
:
return
$this
->
_blockName
;
break
;
case
'function_name'
:
return
$this
->
_functionName
;
break
;
case
'start_pos'
:
case
'end_pos'
:
case
'template'
:
if
(!
array_key_exists
(
$info_type
,
$this
->
_blockLocation
))
{
// invalid block name
return
'invalid block name'
;
}
return
$this
->
_blockLocation
[
$info_type
];
break
;
case
'template_file'
:
return
$this
->
_getTemplateFile
(
true
);
break
;
case
'content'
:
$template_body
=
file_get_contents
(
$this
->
_getTemplateFile
()
);
$length
=
$this
->
_blockLocation
[
'end_pos'
]
-
$this
->
_blockLocation
[
'start_pos'
];
return
substr
(
$template_body
,
$this
->
_blockLocation
[
'start_pos'
],
$length
);
break
;
}
return
'undefined'
;
}
/**
* Main template being edited (parse copy, instead of original)
*
* @return bool
*/
function
_isMainTemplate
()
{
return
$this
->
_blockLocation
[
'template'
]
==
$this
->
_sourceTemplate
;
}
/**
* Returns filename, that contains template, where block is located
*
* @return string
*/
function
_getTemplateFile
(
$relative
=
false
,
$extension
=
'.tpl'
)
{
$filename
=
$this
->
Application
->
TemplatesCache
->
GetRealFilename
(
$this
->
_blockLocation
[
'template'
]
)
.
$extension
;
if
(
$relative
)
{
$filename
=
preg_replace
(
'/^'
.
preg_quote
(
FULL_PATH
,
'/'
)
.
'/'
,
''
,
$filename
,
1
);
}
return
$filename
;
}
/**
* Saves new version of block to template, where it's located
*
* @param kDBItem $object
*/
function
saveBlock
(&
$object
)
{
$main_template
=
$this
->
_isMainTemplate
();
$filename
=
$this
->
_getTemplateFile
(
false
);
// 1. get new template content
$new_template_body
=
$this
->
_getNewTemplateContent
(
$object
,
$filename
,
$lines_before
);
if
(
is_bool
(
$new_template_body
)
&&
(
$new_template_body
===
true
))
{
// when nothing changed -> stop processing
return
true
;
}
// 2. backup original template
if
(!
$main_template
&&
!
copy
(
$filename
,
$filename
.
'.bak'
))
{
// backup failed
$error_file
=
$this
->
_getTemplateFile
(
true
,
'.tpl.bak'
);
$object
->
SetError
(
'FileContents'
,
'template_backup_failed'
,
'+Failed to create backup template "<strong>'
.
$error_file
.
'</strong>" backup.'
);
return
false
;
}
// 3. save changed template
$save_filename
=
$this
->
_getTemplateFile
(
false
,
$main_template
?
'.tmp.tpl'
:
'.tpl'
);
$fp
=
fopen
(
$save_filename
,
'w'
);
if
(!
$fp
)
{
// backup template create failed OR existing template save
$error_file
=
$this
->
_getTemplateFile
(
true
,
$main_template
?
'.tmp.tpl'
:
'.tpl'
);
$object
->
SetError
(
'FileContents'
,
'template_changes_save_failed'
,
'+Failed to save template "<strong>'
.
$error_file
.
'</strong>" changes.'
);
return
false
;
}
fwrite
(
$fp
,
$new_template_body
);
fclose
(
$fp
);
// 3. parse template to check for errors
$this
->
_parseTemplate
(
$object
,
$main_template
?
'.tmp'
:
''
);
if
(
$this
->
_parseErrors
)
{
$error_msg
=
Array
();
foreach
(
$this
->
_parseErrors
as
$error_data
)
{
if
(
preg_match
(
'/line ([
\d
]+)/'
,
$error_data
[
'msg'
],
$regs
))
{
// another line number inside message -> patch it
$error_data
[
'msg'
]
=
str_replace
(
'line '
.
$regs
[
1
],
'line '
.
(
$regs
[
1
]
-
$lines_before
),
$error_data
[
'msg'
]);
}
$error_msg
[]
=
$error_data
[
'msg'
]
.
' at line '
.
(
$error_data
[
'line'
]
-
$lines_before
);
}
$object
->
SetError
(
'FileContents'
,
'template_syntax_error'
,
'+Template syntax errors:<br/>'
.
implode
(
'<br/>'
,
$error_msg
));
return
false
;
}
if
(
$main_template
)
{
// 4.1. replace original file with temporary
if
(!
rename
(
$this
->
_getTemplateFile
(
false
,
'.tmp.tpl'
),
$filename
))
{
// failed to save new content to original template
$error_file
=
$this
->
_getTemplateFile
(
true
);
$object
->
SetError
(
'FileContents'
,
'template_save_failed'
,
'+Failed to save template "<strong>'
.
$error_file
.
'</strong>".'
);
return
false
;
}
}
else
{
// 4.2. delete backup
unlink
(
$this
->
_getTemplateFile
(
false
,
'.tpl.bak'
)
);
}
return
true
;
}
/**
* Returns new template content of "true", when nothing is changed
*
* @param kDBItem $object
* @param string $filename
* @param int $lines_before
* @return mixed
*/
function
_getNewTemplateContent
(&
$object
,
$filename
,
&
$lines_before
)
{
$new_content
=
$object
->
GetDBField
(
'FileContents'
);
$template_body
=
file_get_contents
(
$filename
);
$lines_before
=
substr_count
(
substr
(
$template_body
,
0
,
$this
->
_blockLocation
[
'start_pos'
]),
"
\n
"
);
$new_template_body
=
substr
(
$template_body
,
0
,
$this
->
_blockLocation
[
'start_pos'
])
.
$new_content
.
substr
(
$template_body
,
$this
->
_blockLocation
[
'end_pos'
]);
return
crc32
(
$template_body
)
==
crc32
(
$new_template_body
)
?
true
:
$new_template_body
;
}
function
_saveError
(
$errno
,
$errstr
,
$errfile
,
$errline
,
$errcontext
)
{
if
(
$errno
!=
E_USER_ERROR
)
{
// ignore all minor errors, except fatals from parser
return
true
;
}
/*if (defined('E_STRICT') && ($errno == E_STRICT)) {
// always ignore strict errors here (specially when not in debug mode)
return true;
}*/
$this
->
_parseErrors
[]
=
Array
(
'msg'
=>
$errstr
,
'file'
=>
$errfile
,
'line'
=>
$errline
);
return
true
;
}
}
Event Timeline
Log In to Comment