Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1050441
cache_updater.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
Wed, Jul 2, 9:43 AM
Size
16 KB
Mime Type
text/x-php
Expires
Fri, Jul 4, 9:43 AM (9 h, 59 m)
Engine
blob
Format
Raw Data
Handle
678695
Attached To
rINP In-Portal
cache_updater.php
View Options
<?php
/**
* @version $Id: cache_updater.php 16814 2024-10-28 11:26:00Z 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.org/license for copyright notices and details.
*/
defined
(
'FULL_PATH'
)
or
die
(
'restricted access!'
);
class
clsRecursionStack
{
var
$Stack
;
/**
* Creates instance of clsRecursionStack class.
*/
public
function
__construct
()
{
$this
->
Stack
=
Array
();
}
function
Push
(
$values
)
{
array_push
(
$this
->
Stack
,
$values
);
}
function
Pop
()
{
if
(
$this
->
Count
()
>
0
)
{
return
array_pop
(
$this
->
Stack
);
}
else
{
return
false
;
}
}
function
Get
()
{
if
(
$this
->
Count
()
>
0
)
{
// return end($this->Stack);
return
$this
->
Stack
[
count
(
$this
->
Stack
)-
1
];
}
else
{
return
false
;
}
}
function
Update
(
$values
)
{
$this
->
Stack
[
count
(
$this
->
Stack
)-
1
]
=
$values
;
}
function
Count
()
{
return
count
(
$this
->
Stack
);
}
}
class
clsCachedPermissions
{
var
$Allow
=
Array
();
var
$Deny
=
Array
();
var
$CatId
;
/**
* Table name used for inserting permissions
*
* @var string
*/
var
$table
=
''
;
/**
* Creates class instance.
*
* @param integer $cat_id Category ID.
* @param string $table_name Table name.
*/
public
function
__construct
(
$cat_id
,
$table_name
)
{
$this
->
CatId
=
$cat_id
;
$this
->
table
=
$table_name
;
}
function
SetCatId
(
$CatId
)
{
$this
->
CatId
=
$CatId
;
}
function
CheckPermArray
(
$Perm
)
{
if
(!
isset
(
$this
->
Allow
[
$Perm
]))
{
$this
->
Allow
[
$Perm
]
=
array
();
$this
->
Deny
[
$Perm
]
=
array
();
}
}
function
AddAllow
(
$Perm
,
$GroupId
)
{
$this
->
CheckPermArray
(
$Perm
);
if
(!
in_array
(
$GroupId
,
$this
->
Allow
[
$Perm
]))
{
array_push
(
$this
->
Allow
[
$Perm
],
$GroupId
);
$this
->
RemoveDeny
(
$Perm
,
$GroupId
);
}
}
function
AddDeny
(
$Perm
,
$GroupId
)
{
$this
->
CheckPermArray
(
$Perm
);
if
(!
in_array
(
$GroupId
,
$this
->
Deny
[
$Perm
]))
{
array_push
(
$this
->
Deny
[
$Perm
],
$GroupId
);
$this
->
RemoveAllow
(
$Perm
,
$GroupId
);
}
}
function
RemoveDeny
(
$Perm
,
$GroupId
)
{
if
(
in_array
(
$GroupId
,
$this
->
Deny
[
$Perm
]))
{
array_splice
(
$this
->
Deny
[
$Perm
],
array_search
(
$GroupId
,
$this
->
Deny
[
$Perm
]),
1
);
}
}
function
RemoveAllow
(
$Perm
,
$GroupId
)
{
if
(
in_array
(
$GroupId
,
$this
->
Allow
[
$Perm
]))
{
array_splice
(
$this
->
Allow
[
$Perm
],
array_search
(
$GroupId
,
$this
->
Allow
[
$Perm
]),
1
);
}
}
function
GetInsertSQL
()
{
$values
=
array
();
foreach
(
$this
->
Allow
as
$perm
=>
$groups
)
{
if
(
count
(
$groups
)
>
0
)
{
$values
[]
=
'('
.
$this
->
CatId
.
', '
.
$perm
.
', "'
.
join
(
','
,
$groups
).
'")'
;
}
}
if
(
!
$values
)
{
return
''
;
}
return
'INSERT INTO `'
.
$this
->
table
.
'` (CategoryId, PermId, ACL) VALUES '
.
join
(
','
,
$values
);
}
}
class
kPermCacheUpdater
extends
kHelper
{
/**
* Holds Stack
*
* @var clsRecursionStack
*/
var
$Stack
;
/**
* Rebuild process iteration
*
* @var int
*/
var
$iteration
;
/**
* Categories count to process
*
* @var unknown_type
*/
var
$totalCats
=
0
;
/**
* Processed categories count
*
* @var int
*/
var
$doneCats
=
0
;
/**
* Temporary table name used for storing cache building progress
*
* @var string
*/
var
$progressTable
=
''
;
/**
* Temporary table name used for storing not fully built permissions cache
* 1. preserves previous cache while new cache is building
* 2. when rebuild process fails allows previous cache (in live table) is used
*
* @var string
*/
var
$permCacheTable
=
''
;
var
$primaryLanguageId
=
0
;
var
$languages
=
Array
();
var
$root_prefixes
=
Array
();
/**
* Update cache only for requested categories and it's parent categories
*
* @var bool
*/
var
$StrictPath
=
false
;
/**
* Returns instance of perm cache updater
*
* @param int $continuing
* @param mixed $strict_path
*/
public
function
__construct
(
$continuing
=
null
,
$strict_path
=
null
)
{
parent
::
__construct
();
if
(
isset
(
$strict_path
)
)
{
if
(
$strict_path
&&
!
is_array
(
$strict_path
)
)
{
$strict_path
=
explode
(
'|'
,
trim
(
$strict_path
,
'|'
));
}
$this
->
StrictPath
=
$strict_path
;
}
// cache widely used values to speed up process
/** @var kMultiLanguageHelper $ml_helper */
$ml_helper
=
$this
->
Application
->
recallObject
(
'kMultiLanguageHelper'
);
$this
->
languages
=
$ml_helper
->
getLanguages
();
$this
->
primaryLanguageId
=
$this
->
Application
->
GetDefaultLanguageId
();
foreach
(
$this
->
Application
->
ModuleInfo
as
$module_name
=>
$module_info
)
{
$this
->
root_prefixes
[
$module_info
[
'RootCat'
]
]
=
$module_info
[
'Var'
];
}
$this
->
iteration
=
0
;
if
(
PHP_SAPI
===
'cli'
)
{
// The progress bar isn't used.
$this
->
progressTable
=
sprintf
(
'permCacheUpdate_%s_%s'
,
time
(),
SecurityGenerator
::
generateBytes
(
8
));
$this
->
permCacheTable
=
sprintf
(
TABLE_PREFIX
.
'CategoryPermissionsCache_%s_%s'
,
time
(),
SecurityGenerator
::
generateBytes
(
8
)
);
}
else
{
// Temporary table name must be the same between redirects for progress bar to work.
$this
->
progressTable
=
$this
->
Application
->
GetTempName
(
'permCacheUpdate'
);
$this
->
permCacheTable
=
$this
->
Application
->
GetTempName
(
TABLE_PREFIX
.
'CategoryPermissionsCache'
);
}
if
(!
isset
(
$continuing
)
||
$continuing
==
1
)
{
$this
->
InitUpdater
();
}
elseif
(
$continuing
==
2
)
{
$this
->
getData
();
}
}
function
InitUpdater
()
{
$this
->
Stack
=
new
clsRecursionStack
();
$this
->
initData
();
}
function
getDonePercent
()
{
if
(!
$this
->
totalCats
)
{
return
0
;
}
return
min
(
100
,
intval
(
floor
(
$this
->
doneCats
/
$this
->
totalCats
*
100
)
));
}
function
getData
()
{
$tmp
=
$this
->
Conn
->
GetOne
(
'SELECT data FROM `'
.
$this
->
progressTable
.
'`'
);
if
(
$tmp
)
{
$tmp
=
unserialize
(
$tmp
);
}
$this
->
totalCats
=
isset
(
$tmp
[
'totalCats'
])
?
$tmp
[
'totalCats'
]
:
0
;
$this
->
doneCats
=
isset
(
$tmp
[
'doneCats'
])
?
$tmp
[
'doneCats'
]
:
0
;
if
(
isset
(
$tmp
[
'stack'
]))
{
$this
->
Stack
=
$tmp
[
'stack'
];
}
else
{
$this
->
Stack
=
new
clsRecursionStack
();
}
}
function
setData
()
{
$tmp
=
Array
(
'totalCats'
=>
$this
->
totalCats
,
'doneCats'
=>
$this
->
doneCats
,
'stack'
=>
$this
->
Stack
,
);
$this
->
Conn
->
Query
(
'DELETE FROM `'
.
$this
->
progressTable
.
'`'
);
$fields_hash
=
Array
(
'data'
=>
serialize
(
$tmp
));
$this
->
Conn
->
doInsert
(
$fields_hash
,
$this
->
progressTable
);
}
function
initData
()
{
$this
->
clearData
();
// drop table before starting anyway
// 1. create table for rebuilding permissions cache
$this
->
Conn
->
Query
(
'CREATE TABLE `'
.
$this
->
permCacheTable
.
'` LIKE `'
.
TABLE_PREFIX
.
'CategoryPermissionsCache`'
);
if
(
$this
->
StrictPath
)
{
// When using strict path leave all other cache intact.
$sql
=
'INSERT INTO `'
.
$this
->
permCacheTable
.
'`
SELECT *
FROM `'
.
TABLE_PREFIX
.
'CategoryPermissionsCache`'
;
$this
->
Conn
->
Query
(
$sql
);
// Delete only cache related to categories in path.
$sql
=
'DELETE FROM `'
.
$this
->
permCacheTable
.
'`
WHERE CategoryId IN ('
.
implode
(
','
,
$this
->
StrictPath
)
.
')'
;
$this
->
Conn
->
Query
(
$sql
);
}
$add_charset
=
defined
(
'SQL_CHARSET'
)
?
' CHARACTER SET '
.
SQL_CHARSET
.
' '
:
''
;
$add_collation
=
defined
(
'SQL_COLLATION'
)
?
' COLLATE '
.
SQL_COLLATION
.
' '
:
''
;
$this
->
Conn
->
Query
(
sprintf
(
'CREATE TABLE `%1$s` (data LONGTEXT%2$s%3$s) %2$s%3$s'
,
$this
->
progressTable
,
$add_charset
,
$add_collation
));
$this
->
totalCats
=
(
int
)
$this
->
Conn
->
GetOne
(
'SELECT COUNT(*) FROM `'
.
TABLE_PREFIX
.
'Categories`'
);
$this
->
doneCats
=
0
;
}
function
clearData
()
{
// some templates use this
$sql
=
'UPDATE '
.
TABLE_PREFIX
.
'SystemSettings
SET VariableValue = VariableValue + 1
WHERE VariableName = "CategoriesRebuildSerial"'
;
$this
->
Conn
->
Query
(
$sql
);
// Always drop temporary tables.
$this
->
Conn
->
Query
(
'DROP TABLE IF EXISTS `'
.
$this
->
progressTable
.
'`'
);
$this
->
Conn
->
Query
(
'DROP TABLE IF EXISTS `'
.
$this
->
permCacheTable
.
'`'
);
$this
->
Application
->
deleteDBCache
(
'ForcePermCacheUpdate'
);
}
function
SaveData
()
{
// copy data from temp permission cache table back to live
$this
->
Conn
->
Query
(
'TRUNCATE '
.
TABLE_PREFIX
.
'CategoryPermissionsCache'
);
$sql
=
'INSERT INTO `'
.
TABLE_PREFIX
.
'CategoryPermissionsCache`
SELECT *
FROM `'
.
$this
->
permCacheTable
.
'`'
;
$this
->
Conn
->
Query
(
$sql
);
$this
->
clearData
();
$this
->
Application
->
incrementCacheSerial
(
'c'
);
}
function
DoTheJob
()
{
$data
=
$this
->
Stack
->
Get
();
if
(
$data
===
false
)
{
//If Stack is empty
$data
[
'current_id'
]
=
0
;
$data
[
'titles'
]
=
Array
();
$data
[
'parent_path'
]
=
Array
();
$data
[
'named_path'
]
=
Array
();
$data
[
'file_name'
]
=
''
;
$data
[
'template'
]
=
''
;
// design
$data
[
'item_template'
]
=
''
;
$data
[
'children_count'
]
=
0
;
$data
[
'left'
]
=
0
;
$data
[
'right'
]
=
2
;
$data
[
'debug_title'
]
=
'ROOT'
;
$this
->
Stack
->
Push
(
$data
);
}
if
(!
isset
(
$data
[
'queried'
]))
{
$this
->
QueryTitle
(
$data
);
$this
->
QueryChildren
(
$data
);
$data
[
'children_count'
]
=
count
(
$data
[
'children'
]);
$this
->
QueryPermissions
(
$data
);
$data
[
'queried'
]
=
1
;
$data
[
'right'
]
=
$data
[
'left'
]+
1
;
$sql
=
$data
[
'perms'
]->
GetInsertSQL
();
if
(
$sql
)
{
$this
->
Conn
->
Query
(
$sql
);
// $this->doneCats++; // moved to the place where it pops out of the stack by Kostja
}
$this
->
iteration
++;
}
// start with first child if we haven't started yet
if
(!
isset
(
$data
[
'current_child'
]))
$data
[
'current_child'
]
=
0
;
// if we have more children on CURRENT LEVEL
if
(
isset
(
$data
[
'children'
][
$data
[
'current_child'
]]))
{
if
(
$this
->
StrictPath
)
{
while
(
isset
(
$data
[
'children'
][
$data
[
'current_child'
]
])
&&
!
in_array
(
$data
[
'children'
][
$data
[
'current_child'
]
],
$this
->
StrictPath
)
)
{
$data
[
'current_child'
]++;
continue
;
}
if
(!
isset
(
$data
[
'children'
][
$data
[
'current_child'
]
]))
return
false
;
//error
}
$next_data
=
Array
();
$next_data
[
'titles'
]
=
$data
[
'titles'
];
$next_data
[
'parent_path'
]
=
$data
[
'parent_path'
];
$next_data
[
'named_path'
]
=
$data
[
'named_path'
];
$next_data
[
'template'
]
=
$data
[
'template'
];
$next_data
[
'item_template'
]
=
$data
[
'item_template'
];
$next_data
[
'current_id'
]
=
$data
[
'children'
][
$data
[
'current_child'
]
];
//next iteration should process child
$next_data
[
'perms'
]
=
clone
$data
[
'perms'
];
// copy permissions to child - inheritance
$next_data
[
'perms'
]->
SetCatId
(
$next_data
[
'current_id'
]);
$next_data
[
'left'
]
=
$data
[
'right'
];
$data
[
'current_child'
]++;
$this
->
Stack
->
Update
(
$data
);
//we need to update ourself for the iteration after the next (or further) return to next child
$this
->
Stack
->
Push
(
$next_data
);
//next iteration should process this child
return
true
;
}
else
{
$this
->
Stack
->
Update
(
$data
);
$prev_data
=
$this
->
Stack
->
Pop
();
//remove ourself from stack if we have finished all the childs (or there are none)
$data
[
'right'
]
=
$prev_data
[
'right'
];
$this
->
UpdateCachedPath
(
$data
);
// we are getting here if we finished with current level, so check if it's first level - then bail out.
$this
->
doneCats
++;
// moved by Kostja from above, seems to fix the prob
$has_more
=
$this
->
Stack
->
Count
()
>
0
;
if
(
$has_more
)
{
$next_data
=
$this
->
Stack
->
Get
();
$next_data
[
'right'
]
=
$data
[
'right'
]+
1
;
$next_data
[
'children_count'
]
+=
$data
[
'children_count'
];
$this
->
Stack
->
Update
(
$next_data
);
}
return
$has_more
;
}
}
function
UpdateCachedPath
(&
$data
)
{
if
(
$data
[
'current_id'
]
==
0
)
{
// don't update non-existing "Home" category
return
;
}
// allow old fashion system templates to work (maybe this is no longer needed, since no such urls after upgrade from 4.3.1)
$named_parent_path
=
strpos
(
$data
[
'file_name'
],
'/'
)
!==
false
?
$data
[
'file_name'
]
:
implode
(
'/'
,
$data
[
'named_path'
]);
$fields_hash
=
Array
(
'ParentPath'
=>
'|'
.
implode
(
'|'
,
$data
[
'parent_path'
])
.
'|'
,
'NamedParentPath'
=>
$named_parent_path
,
// url component for a category page
'NamedParentPathHash'
=>
kUtil
::
crc32
(
mb_strtolower
(
preg_replace
(
'/^Content
\/
/i'
,
''
,
$named_parent_path
))),
'CachedTemplate'
=>
$data
[
'template'
],
// actual template to use when category is visited
'CachedTemplateHash'
=>
kUtil
::
crc32
(
mb_strtolower
(
$data
[
'template'
])),
'CachedDescendantCatsQty'
=>
$data
[
'children_count'
],
'TreeLeft'
=>
$data
[
'left'
],
'TreeRight'
=>
$data
[
'right'
],
);
foreach
(
$this
->
languages
as
$language_id
)
{
$fields_hash
[
'l'
.
$language_id
.
'_CachedNavbar'
]
=
implode
(
'&|&'
,
$data
[
'titles'
][
$language_id
]);
}
$this
->
Conn
->
doUpdate
(
$fields_hash
,
TABLE_PREFIX
.
'Categories'
,
'CategoryId = '
.
$data
[
'current_id'
]);
if
(
$this
->
Conn
->
getAffectedRows
()
>
0
)
{
$this
->
Application
->
incrementCacheSerial
(
'c'
,
$data
[
'current_id'
]);
}
}
function
QueryTitle
(&
$data
)
{
$category_id
=
$data
[
'current_id'
];
$sql
=
'SELECT *
FROM '
.
TABLE_PREFIX
.
'Categories
WHERE CategoryId = '
.
$category_id
;
$record
=
$this
->
Conn
->
GetRow
(
$sql
);
if
(
$record
)
{
foreach
(
$this
->
languages
as
$language_id
)
{
$data
[
'titles'
][
$language_id
][]
=
$record
[
'l'
.
$language_id
.
'_Name'
]
?
$record
[
'l'
.
$language_id
.
'_Name'
]
:
$record
[
'l'
.
$this
->
primaryLanguageId
.
'_Name'
];
}
$data
[
'debug_title'
]
=
$record
[
'l1_Name'
];
$data
[
'parent_path'
][]
=
$category_id
;
$data
[
'named_path'
][]
=
preg_replace
(
'/^Content
\\
//'
,
''
,
$record
[
'Filename'
]);
$data
[
'file_name'
]
=
$record
[
'Filename'
];
// it is one of the modules root category
/*$root_prefix = isset($this->root_prefixes[$category_id]) ? $this->root_prefixes[$category_id] : false;
if ( $root_prefix ) {
$fields_hash = Array ();
if ( !$record['Template'] ) {
$record['Template'] = $this->Application->ConfigValue($root_prefix . '_CategoryTemplate');
$fields_hash['Template'] = $record['Template'];
}
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Categories', 'CategoryId = ' . $category_id);
}*/
// if explicitly set, then use it; use parent template otherwise
if
(
$record
[
'Template'
]
&&
(
$record
[
'Template'
]
!=
CATEGORY_TEMPLATE_INHERIT
))
{
$data
[
'template'
]
=
$record
[
'Template'
];
}
}
}
function
QueryChildren
(&
$data
)
{
$sql
=
'SELECT CategoryId
FROM '
.
TABLE_PREFIX
.
'Categories
WHERE ParentId = '
.
$data
[
'current_id'
];
$data
[
'children'
]
=
$this
->
Conn
->
GetCol
(
$sql
);
}
function
QueryPermissions
(&
$data
)
{
// don't search for section "view" permissions here :)
$sql
=
'SELECT ipc.PermissionConfigId, ip.GroupId, ip.PermissionValue
FROM '
.
TABLE_PREFIX
.
'Permissions AS ip
LEFT JOIN '
.
TABLE_PREFIX
.
'CategoryPermissionsConfig AS ipc ON ipc.PermissionName = ip.Permission
WHERE (CatId = '
.
$data
[
'current_id'
].
') AND (Permission LIKE "%.VIEW") AND (ip.Type = 0)'
;
$records
=
$this
->
Conn
->
Query
(
$sql
);
//create permissions array only if we don't have it yet (set by parent)
if
(!
isset
(
$data
[
'perms'
]))
{
$data
[
'perms'
]
=
new
clsCachedPermissions
(
$data
[
'current_id'
],
$this
->
permCacheTable
);
}
foreach
(
$records
as
$record
)
{
if
(
$record
[
'PermissionValue'
]
==
1
)
{
$data
[
'perms'
]->
AddAllow
(
$record
[
'PermissionConfigId'
],
$record
[
'GroupId'
]);
}
else
{
$data
[
'perms'
]->
AddDeny
(
$record
[
'PermissionConfigId'
],
$record
[
'GroupId'
]);
}
}
}
/**
* Rebuild all cache in one step
*
* @param string $path
* @return void
*/
function
OneStepRun
(
$path
=
''
)
{
$this
->
InitUpdater
();
$needs_more
=
true
;
while
(
$needs_more
)
{
// until proceeded in this step category count exceeds category per step limit
$needs_more
=
$this
->
DoTheJob
();
}
$this
->
SaveData
();
}
}
Event Timeline
Log In to Comment