User:JBHansson
Jan B. Hansson
Location:
- Århus, Danmark
Education:
- Carpenter
- Bachelor of Science in Engineering
- IT specialist and Developer
Occupation:
- 1977-1988 COWIconsult - dev. of computer plotted highway and infrastructure design (incl 4 years stationed in Riyadh, Saudi Arabia)
- 1988-2003 TDC Telecom Company - dev. of Geographical Information System
- 2003-2008 CSC Consulting Group - dev. of Geographical Information System
- 2008-2010 CSC ScandiHealth - dev. of Helth Care System
Programming Platform and Technology
- 1977-1992 Pr1me (Fortran) and Intergraph
- 1992-2010 Microsoft (VB, C#, Asp .NET, IIS, SQLserver)
- 2011-2015 TNG, Legacy, Ancestry, MyHeritage
- 2015-20xx TNG, Legacy (php, javascript, MySQL, CodeIgniter Framework)
My Genealogy Web Sites
- Our Xuri.dk Homepage (CodeIgniter Web site)
- The Hansson Tribe (TNG install in CodeIgniter Web site)
- Genealogy Toolbox ( Danish Research Tools in CodeIgniter Web site)
- Swedish America Heritage Online (TNG Web site)
- DIS-Danmark membership page (Slægt og Data medlemsside)
TNG procedures in use
One way sync of genealogy person data from Legacy8 to TNG
In genealogy use only one way sync (mirror copy) from a master to a slave tool.
It is my experience never to do two way sync between tools from different makers. It will create merging problems. We can end up with different persons sharing the same personID and family relations.
|
Analyzing the Living Flag / Death Facts distribution in tng_people table
Here are 4 sql scripts to analyze what are the distribution of the Living Flag / Death Facts in the tng_people table. The sum of the number of records the 4 script will return must be equal to the number of records in the table.
[2] Record list where Living Flag = 0 (dead) and Dead Facts is present [3] Record list where Living Flag = 0 (dead) and Dead Facts is Not present [4] Record list where Living Flag = 1 (alive) and Dead Facts is present NB: |
Area Search on Timeline
A tool for analyzing all people, with a event link to a selected area, presented on a timeline is useful for providing an overview and to find defects in genealogy data.
SELECT
concat('<B>', YEAR(IF(p.birthdatetr, p.birthdatetr, IF(p.altbirthdatetr, p.altbirthdatetr, IF(FamRoleHusband.marrdatetr, FamRoleHusband.marrdatetr, IF(FamRoleWife.marrdatetr, FamRoleWife.marrdatetr, IF(p.deathdatetr, p.deathdatetr, p.burialdatetr)))))),'</B>') AS Timeline,
concat(concat('<H4><B>', p.firstname, ' ', p.lastname, ' ', p.suffix,'</B></H4>'),
'<a href=pedigree.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',"Pedigree",'</a>'," ",
'<a href=getperson.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',p.personID,'</a>'," ",
'<a href=descend.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',"Descend",'</a>',
"\r\rC: ",IF (FamRoleChild.familyID IS NULL," ",Concat('<a href=familychart.php?familyID=',FamRoleChild.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleChild.familyID,'</a>'))," ",
" P: ",IF (FamRoleWife.familyID IS NULL, IF (FamRoleHusband.familyID IS NULL, " ", Concat('<a href=familychart.php?familyID=',FamRoleHusband.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleHusband.familyID,'</a>')), Concat('<a href=familychart.php?familyID=',FamRoleWife.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleWife.familyID,'</a>'))
) AS Person,
concat('<a href=getperson.php?personID=',concat_ws(" ",FamRoleHusband.wife, FamRoleWife.husband),'&tree=TheHanssonTribe Target=\'_blank\'>',concat_ws(" ",FamRoleHusband.wife, FamRoleWife.husband),'</a>')
AS Partner,
concat("B: ",birthdate,"\rC: ",altbirthdate,"\rM: ",concat_ws(" ",FamRoleHusband.marrdate, FamRoleWife.marrdate),"\rD: ",deathdate,"\rB: ",burialdate) AS Event_Date,
concat("B: ",birthplace,"\rC: ",altbirthplace,"\rM: ",concat_ws(" ",FamRoleHusband.marrplace, FamRoleWife.marrplace),"\rD: ",deathplace,"\rB: ",burialplace) AS Event_Place,
concat(p.gedcom,"\r\r",p.branch) AS Tree_Branch
FROM tng1111_people AS p
LEFT JOIN tng1111_families AS groom ON (p.gedcom = groom.gedcom AND p.personID = groom.husband )
LEFT JOIN tng1111_families AS bride ON (p.gedcom = bride.gedcom AND p.personID = bride.wife )
LEFT JOIN tng1111_families AS FamRoleHusband ON (p.gedcom = FamRoleHusband.gedcom AND p.personID = FamRoleHusband.husband )
LEFT JOIN tng1111_families AS FamRoleWife ON (p.gedcom = FamRoleWife.gedcom AND p.personID = FamRoleWife.wife )
LEFT JOIN tng1111_children AS FamRoleChild ON (p.gedcom = FamRoleChild.gedcom AND p.personID = FamRoleChild.personID )
where p.gedcom = "TheHanssonTribe" AND groom.marrplace LIKE "%Danmark%" OR bride.marrplace LIKE "%Danmark%"
UNION DISTINCT
SELECT
concat('<B>', YEAR(IF(p.birthdatetr, p.birthdatetr, IF(p.altbirthdatetr, p.altbirthdatetr, IF(FamRoleHusband.marrdatetr, FamRoleHusband.marrdatetr, IF(FamRoleWife.marrdatetr, FamRoleWife.marrdatetr, IF(p.deathdatetr, p.deathdatetr, p.burialdatetr)))))),'</B>') AS Timeline,
concat(concat('<H4><B>', p.firstname, ' ', p.lastname, ' ', p.suffix,'</B></H4>'),
'<a href=pedigree.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',"Pedigree",'</a>'," ",
'<a href=getperson.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',p.personID,'</a>'," ",
'<a href=descend.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',"Descend",'</a>',
"\r\rC: ",IF (FamRoleChild.familyID IS NULL," ",Concat('<a href=familychart.php?familyID=',FamRoleChild.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleChild.familyID,'</a>'))," ",
" P: ",IF (FamRoleWife.familyID IS NULL, IF (FamRoleHusband.familyID IS NULL, " ", Concat('<a href=familychart.php?familyID=',FamRoleHusband.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleHusband.familyID,'</a>')), Concat('<a href=familychart.php?familyID=',FamRoleWife.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleWife.familyID,'</a>'))
) AS Person,
concat('<a href=getperson.php?personID=',concat_ws(" ",FamRoleHusband.wife, FamRoleWife.husband),'&tree=TheHanssonTribe Target=\'_blank\'>',concat_ws(" ",FamRoleHusband.wife, FamRoleWife.husband),'</a>')
AS Partner,
concat("B: ",birthdate,"\rC: ",altbirthdate,"\rM: ",concat_ws(" ",FamRoleHusband.marrdate, FamRoleWife.marrdate),"\rD: ",deathdate,"\rB: ",burialdate) AS Event_Date,
concat("B: ",birthplace,"\rC: ",altbirthplace,"\rM: ",concat_ws(" ",FamRoleHusband.marrplace, FamRoleWife.marrplace),"\rD: ",deathplace,"\rB: ",burialplace) AS Event_Place,
concat(p.gedcom,"\r\r",p.branch) AS Tree_Branch
FROM tng1111_people AS p
LEFT JOIN tng1111_families AS FamRoleHusband ON (p.gedcom = FamRoleHusband.gedcom AND p.personID = FamRoleHusband.husband )
LEFT JOIN tng1111_families AS FamRoleWife ON (p.gedcom = FamRoleWife.gedcom AND p.personID = FamRoleWife.wife )
LEFT JOIN tng1111_children AS FamRoleChild ON (p.gedcom = FamRoleChild.gedcom AND p.personID = FamRoleChild.personID )
where p.gedcom = "TheHanssonTribe" AND p.birthplace LIKE "%Danmark%" OR p.altbirthplace LIKE "%Danmark%" OR p.deathplace LIKE "%Danmark%" OR p.burialplace LIKE "%Danmark%"
UNION DISTINCT
SELECT
concat('<B>', YEAR(IF(p.birthdatetr, p.birthdatetr, IF(p.altbirthdatetr, p.altbirthdatetr, IF(FamRoleHusband.marrdatetr, FamRoleHusband.marrdatetr, IF(FamRoleWife.marrdatetr, FamRoleWife.marrdatetr, IF(p.deathdatetr, p.deathdatetr, p.burialdatetr)))))),'</B>') AS Timeline,
concat(concat('<H4><B>', p.firstname, ' ', p.lastname, ' ', p.suffix,'</B></H4>'),
'<a href=pedigree.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',"Pedigree",'</a>'," ",
'<a href=getperson.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',p.personID,'</a>'," ",
'<a href=descend.php?personID=',p.personID,'&tree=TheHanssonTribe Target=\'_blank\'>',"Descend",'</a>',
"\r\rC: ",IF (FamRoleChild.familyID IS NULL," ",Concat('<a href=familychart.php?familyID=',FamRoleChild.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleChild.familyID,'</a>'))," ",
" P: ",IF (FamRoleWife.familyID IS NULL, IF (FamRoleHusband.familyID IS NULL, " ", Concat('<a href=familychart.php?familyID=',FamRoleHusband.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleHusband.familyID,'</a>')), Concat('<a href=familychart.php?familyID=',FamRoleWife.familyID,'&tree=TheHanssonTribe Target=\'_blank\'>',FamRoleWife.familyID,'</a>'))
) AS Person,
concat('<a href=getperson.php?personID=',concat_ws(" ",FamRoleHusband.wife, FamRoleWife.husband),'&tree=TheHanssonTribe Target=\'_blank\'>',concat_ws(" ",FamRoleHusband.wife, FamRoleWife.husband),'</a>')
AS Partner,
concat("B: ",birthdate,"\rC: ",altbirthdate,"\rM: ",concat_ws(" ",FamRoleHusband.marrdate, FamRoleWife.marrdate),"\rD: ",deathdate,"\rB: ",burialdate) AS Event_Date,
concat("B: ",birthplace,"\rC: ",altbirthplace,"\rM: ",concat_ws(" ",FamRoleHusband.marrplace, FamRoleWife.marrplace),"\rD: ",deathplace,"\rB: ",burialplace) AS Event_Place,
concat(p.gedcom,"\r\r",p.branch) AS Tree_Branch
FROM tng1111_people AS p
LEFT JOIN tng1111_events AS persev ON (p.gedcom = persev.gedcom AND p.personID = persev.persfamID )
LEFT JOIN tng1111_families AS FamRoleHusband ON (p.gedcom = FamRoleHusband.gedcom AND p.personID = FamRoleHusband.husband )
LEFT JOIN tng1111_families AS FamRoleWife ON (p.gedcom = FamRoleWife.gedcom AND p.personID = FamRoleWife.wife )
LEFT JOIN tng1111_children AS FamRoleChild ON (p.gedcom = FamRoleChild.gedcom AND p.personID = FamRoleChild.personID )
where p.gedcom = "TheHanssonTribe" AND persev.eventplace LIKE "%Danmark%"
ORDER BY Timeline, Event_Date
|
TNG customizations in use
Google Search and Go
The design goal of Google Search and Go is to add a search widget to the TNG Advanced Search page that lets your users use Google to search your own site, or any other sites that you identify through a configuration file. Also allows you to define links that your users can follow, and links that only administrators can follow. A co-development with Robin Richmond
NB: This MOD has been obsolite in TNG 11.0.0 replaced by Search this site and the original MOD was moved to Genealogy Toolbox
Visual Familytree Walking
The design goal of Visual Familytree Walking is to achieve that the user will have a very user-friendly opportunity with few mouse clicks quickly and visually to move around in the whole interrelated familytree (when there are no islands) - chart after chart in both ancestor and descendant direction and thereby be able to visit every person present in the familytree. A co-development with Chuck Filteau. Demo of Visual Familytree Walking
MakeUp Appearance
The design goal of MakeUp Appearance is to give the user the opportunity to customize the appearance of TNG to the user's taste. The appearence is achieved by applaying the style from the 15 TNG templates. Demo of MakeUp Appearance
TNG Mods I use
I have the following TNG mods installed on my web site:
TNG Extensions by Best Practice
Here follows some recipes on what I consider to be Best Practice in developing TNG Extensions. My expirence has been obtained over many years partly in professional IT companies and partly after retirement to play with changes and additions to TNG and working with the CodeIgniter3 Framework.
TNG Extensions by Design
The golden age for the lonely cowboy developer are definitely behind us. He was the only one who could overlook big spagiti programs, where one little change in one place could trigger errors elsewhere in the program. The software industry found a simple solution in the component industri. Divide and isolate the spagite programs into separate, isolated and independent components. Separate program parts in boxes with very little connection between boxes and allow only familiar and verifiable connections (interfaces) between boxes.
TNG Extensions Design Goals and Guidelines
Therefore following design goals and guidelines of TNG extensions can be listed:
- Build extensions on the component idea to make TNG and component maintenance and upgrades more flawless
- The component may well be aware of TNG inside content (user,language etc), but TNG should not be aware of the components internals.
- Make as few and well-defined interface connections from component into TNG to make as little impact as possible.
On the figur to the right with the TNG root folder are outlined by a wall to separate what is Darrins TNG code zone and what belongs to the extension code zone. The goal is to keep the 2 code zones divided with as little impact on TNG as posible.
When building the MOD Google Search and Go in 2015, we had in tnguser2 discussions about best practice for MOD development. Could we use the TNG folder extensions in order not to mix own code with TNG code and it stranded on not have a solution to make it practical posible.
Since then I have created a proxy solution that works and have used it almost 2 years. It is described in section TNG extensions by Proxy.
To the repeated problems with TNG/MOD mixing of config and language code, I have found a practical solution for presented in the section TNG extensions by Config and section TNG extensions by Language
TNG Extensions by Proxy
Of the 3 proxy parts described here only _proxy_exec.php and _proxy_error.php has to be placed in the TNG root folder. Both their names start with underscores to make them surface the TNG files.
NB. After using the described proxy system on my website for almost 2 years to run multiple calls by proxy, I encountered one php feature PHP_SELF that will fail. A search shows that PHP_SELF is not used in TNG probably due to security reasons and because there exist other solutions - see https://www.dzhang.com/blog/2013/05/20/php_self-and-cross-site-scripting
_proxy_job.php
The short snippet code showen in the _proxy_job.php file is the job description included and used in the _proxy_exec.php file. The php begin tag are followed by 4 commented out lines containing the job instructions template to follow. Then comes 2 set of job descriptions that actuelly can be testet and they will result in the 2 links - the first will execute a PHP file located in a extensions subfolder and the second a PDF file as described is actuelly located in a path outside the TNG folder (placed in CodeIgniter folder structure). And I found 2 that are allowed by guest visitors. The proxy system will fail if the visitor is not matching the allow key. One nice safty thing is that the path and filename is not showen to the visitors address line.
https://xuri.dk/Genealogy/_proxy_exec.php?job=mb_008
https://xuri.dk/Genealogy/_proxy_exec.php?job=mbww2
<?php
// Proxy Job description - include ("extensions/T99/t99_proxy_job.php");
// $proxy_idx['x'] = "_proxy_exec.php?job=x";
// $proxy_fil['x'] = "path/filename";
// $proxy_key['x'] = "allow_admin|allow_user|allow_guest,filetype_php|filetype_html|filetype_pdf";
$proxy_job['mb_008'] = "_proxy_exec.php?job=mb_008";
$proxy_fil['mb_008'] = "../assets/tng/pdf/mbww2/008_mandem_bag_det_hele.pdf";
$proxy_key['mb_008'] = "allow_guest,filetype_pdf";
$proxy_job['mbww2'] = "_proxy_exec.php?job=mbww2";
$proxy_fil['mbww2'] = "extensions/T99/cmp_mbww2/t99_cmp_mbww2.php";
$proxy_key['mbww2'] = "allow_guest,filetype_php";
?>
_proxy_exec.php
The short but complete code in the _proxy_exec.php file is the driving force behind the entire proxy solution. The php begin tag are followed by 6 include files representing 6 components in subfolders of the extensions folder containing job instructions to be handled by the _proxy_exec.php
<?php
@include ("extensions/ADM/SAM/adm_sam_proxy_job.php");
@include ("extensions/T99/cmp_places/t99_proxy_job.php");
@include ("extensions/T99/cmp_ba1976/t99_proxy_job.php");
@include ("extensions/T99/cmp_mbww2/t99_proxy_job.php");
@include ("extensions/T99/cmp_portrait/t99_proxy_job.php");
@include ("extensions/T99/t99_proxy_job.php");
$task_job = (isset($_GET["job"])) ? $_GET["job"] : redirectTo("_proxy_error.php?code=401");
$task_fil = $proxy_fil[$task_job];
$task_key = $proxy_key[$task_job];
session_start();
if ( stripos($task_key, "allow_admin") !== false) if ($_SESSION['allow_admin'] == 0) redirectTo("login.php"); else goto branch_filetype;
if ( stripos($task_key, "allow_user" ) !== false) if ($_SESSION['allow_living'] == 0) redirectTo("login.php"); else goto branch_filetype;
if ( stripos($task_key, "allow_guest") !== false) goto branch_filetype; else redirectTo("_proxy_error.php?code=402");
branch_filetype:
if ( stripos($task_key, "filetype_php") !== false ) @include $task_fil;
if ( stripos($task_key, "filetype_html" ) !== false) redirectTo($task_fil);
if ( stripos($task_key, "filetype_pdf") !== false) {
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . basename($task_fil) . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
readfile($task_fil);
}
exit;
function redirectTo($url){header ("Location: " . $url);exit;}
?>
_proxy_error.php
Only a part of a big file with many error codes used to call with an error code it will handle redirection and showing message to the visitor.
<?php
$code_index = (isset($_GET["code"])) ? $_GET["code"] : "100";
// https://help.dreamhost.com/hc/en-us/articles/215840318-Custom-error-pages
$page_redirected_from = $_SERVER['REQUEST_URI']; // this is especially useful with error 404 to indicate the missing page.
$server_url = "http://" . $_SERVER["SERVER_NAME"] . "/";
//$redirect_url = $_SERVER["REDIRECT_URL"];
//$redirect_url_array = parse_url($redirect_url);
//$end_of_path = strrchr($redirect_url_array["path"], "/");
$redirect_to = $explanation = $error_code = "";
//switch(getenv("REDIRECT_STATUS"))
switch($code_index)
{
case 401:
$error_code = "401 - Unauthorized";
$explanation = "The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in HTTP Authentication: Basic and Digest Access Authentication
This section requires a password or is otherwise protected. If you feel you have reached this page in error, please return to the login page and try again, or contact the webmaster if you continue to have problems.";
$redirect_to = "";
break;
case 403:
$error_code = "403 - Forbidden";
$explanation = "The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
This section requires a password or is otherwise protected. If you feel you have reached this page in error, please return to the login page and try again, or contact the webmaster if you continue to have problems.";
$redirect_to = "";
break;
case 404:
$error_code = "404 - Not Found";
$explanation = "The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.
The requested resource '" . $page_redirected_from . "' could not be found on this server. Please verify the address and try again.";
$redirect_to = $server_url . "wiki" . $end_of_path;
break;
case 999:
$error_code = "999 - Program part needs login";
$explanation = "Program part needs login";
$redirect_to = "login.php";
break;
};
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="Shortcut Icon" href="/favicon.ico" type="image/x-icon" />
<?php
if ($redirect_to != "")
{
?>
<meta http-equiv="Refresh" content="10; url='<?php print($redirect_to); ?>'">
<?php
}
?>
<title>Page not found: <?php print ($redirect_to); ?></title>
</head>
<body>
<h1>Error Code <?php print ($error_code); ?></h1>
<p>The <a href="http://en.wikipedia.org/wiki/Uniform_resource_locator">URL</a> you requested was not found. <?PHP echo($explanation); ?></p>
<p><strong>Did you mean to type <a href="<?php print ($redirect_to); ?>"><?php print ($redirect_to); ?></a>?</strong> You will be automatically redirected there in 10 seconds.</p>
<p>You may also want to try starting from the home page: <a href="<?php print ($server_url); ?>"><?php print ($server_url); ?></a></p>
<hr />
<p><i>A project of <a href="<?php print ($server_url); ?>"><?php print ($server_url); ?></a>.</i></p>
</body>
</html>
<?php
?>
TNG Extensions by Config
After reading this link I found the config way to use locally in extensions components with explanations why.
https://www.abeautifulsite.net/a-better-way-to-write-config-files-in-php
As an example are here the config file used in the SAM component
<?php
return [
'sam_visitor_probe' => 'RUNNING', // values are RUNNING or STOPPED
'sam_visitor_debug' => 'OFF', // values are ON or OFF
'access_table' => 'xuri_adm_sam_visitor', // Visitor table
'request_table' => 'xuri_adm_sam_request', // Request table
'sitestat_table' => 'xuri_adm_sam_sitestat', // Site Stat table
'SitePrefix' => 'https://xuri.dk', // Site prefix added to link requests
'save_request_blue' => 'N', // values are Y or N
'save_request_green' => 'Y', // values are Y or N
'save_request_grey' => 'Y', // values are Y or N
'save_request_red' => 'Y', // values are Y or N
'save_request_yellow' => 'N', // values are Y or N
'incl_inview_blue' => 'N', // values are Y or N
'incl_inview_green' => 'Y', // values are Y or N
'incl_inview_grey' => 'Y', // values are Y or N
'incl_inview_red' => 'N', // values are Y or N
'incl_inview_yellow' => 'N', // values are Y or N
'fastest_access' => 1.0, // seconds between accesses to be considered fast. 1.0 is faster than most indexers
'rip_ban' => 6, // number of fast clicks without a reset before banned
'rip_warn' => 3, // number of fast clicks without a reset before a warning
'rip_reset' => 4, // fast click reset time in seconds
'rip_ban_time' => 60, // ban time in seconds
'max_recent_hits' => 30, // number of consecutive hits before a captcha challenge is initiated (set to 0 to disable)
'reset_recent_hits' => 3600 * 8, // # of seconds before a reset of the rip_challenge hit tracker (default 8 hours)
'abuseipdb_appkey' => 'qc..........0H1', // Jan - get your personal key at abuseipdb.com
'Website_owner' => 'Jan B. Hansson',
'Website_url' => 'Xuri.dk',
'TNG_Name' => '©TheHanssonTribe',
'TNG_Type' => 'open TNG',
'GMT_offset_sec' => 2 * 3600, // Denmark +2 (summer) +1 (winther) hours to GMT - https://greenwichmeantime.com/time-zone/
'max_images_num' => 28 // nos of random images (images_[1] .... images_[max])
];
?>
Now I don not need TNG's config system inside the component and to change to an array is just easy to work and do many things with. As a standard in my php files the now start like this:
<?php
$SAM_CFG = include('extensions/ADM/SAM/adm_sam_visitor_config.php');
if ($SAM_CFG['sam_visitor_debug'] == "ON") {
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
}
and functions using config like this:
function viewConfig() {
Global $SAM_CFG;
and debug like this:
// Send debug code to the Javascript console
function debug_to_console($data) {
Global $SAM_CFG;
if ($SAM_CFG['sam_visitor_debug'] != 'ON') return;
if(is_array($data) || is_object($data))
echo("<script>console.log('PHP: ".json_encode($data)."');</script>");
else
echo("<script>console.log('PHP: ".$data."');</script>");
}
?>
TNG Extensions by Language
Also for the language area, it is a good idea to be self-sufficient inside the closed component and not be dependent on the TNG language. I create own local language files for each language area corresponding to TNG's language files and then have a language switcher to select the current language file
<?php
//---------------------------------------------------------------------------
// A pre-condition for the parameter $session_language has got a value, is that
// the parent program that includes t99_language_switcher.php previously has
// includeret getlang.php - otherwise the default language will be selected
// ----------------------------------------------------------------------------->
switch ($session_language) {
case "English-UTF8":
include "extensions/ADM/SAM/lang/sam_lang_english_utf8.php";
break;
case "Danish-UTF8":
include "extensions/ADM/SAM/lang/sam_lang_danish_utf8.php";
break;
case "Norwegian-UTF8":
include "extensions/ADM/SAM/lang/sam_lang_norwegian_utf8.php";
break;
case "Swedish-UTF8":
include "extensions/ADM/SAM/lang/sam_lang_swedish_utf8.php";
break;
default:
include "extensions/T99/lang/t99_lang_english_utf8.php";
}
?>
TNG Extensions by Install
Following TNG Extensions Design Goals and Guidelines in the making of the SAM component, I have created a SAM sub-sub folder under the extensions folder containing in one place all off the component parts I can zip or copy install. In the setup folder are 3 sql scripts for creating the external sql tables and the 2 files _proxy_error.php and _proxy_exec.php to be copied (if they do not already exsist) to the TNG root folder. The last missing task is to make the connection into TNG code. Establish menus to call the proxy system with the right job argument. Finally also a README.txt file with installation description (a MOD is not yet produced). It is easy this way also when TNG upgrades it is all in a folder just to copy to the new version and connect the component.
TNG extensions by Example (SAM)
Site Access Manager (SAM) is my latest component build after the described guidelines. SAM's functionality is best described using the SAM report menu to run via the proxy system: