加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
admin.php 115.41 KB
一键复制 编辑 原始数据 按行查看 历史
墨涩 提交于 2020-02-18 10:12 . v1.0升级
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424
<?php
/*******************************************************************
* Glype is copyright and trademark 2007-2016 UpsideOut, Inc. d/b/a Glype
* and/or its licensors, successors and assigners. All rights reserved.
*
* Use of Glype is subject to the terms of the Software License Agreement.
* http://www.glype.com/license.php
*******************************************************************
* This is a stand-alone admin control panel for the Glype software.
******************************************************************/
/*****************************************************************
* Configuration - edit this section (if you want!)
******************************************************************/
# Path to the /includes/settings.php file. Change if you want to move
# this admin script out of the glype directory. You can use a relative
# or absolute path to the file.
define('ADMIN_GLYPE_SETTINGS', 'includes/settings.php');
# How long to keep an inactive admin session open for? After this
# period of inactivity, an admin session is invalidated and you
# must log in again. [seconds]
define('ADMIN_TIMEOUT', 60*60);
# Log viewer limit for collated stats. Limits "most viewed" to
# the top X websites.
define('ADMIN_STATS_LIMIT', 50);
# End of configuration.
/*****************************************************************
* Initialize admin script
******************************************************************/
# Setup error reporting
error_reporting(E_ALL);
ini_set('display_errors', 1);
# Define a path to us
define('ADMIN_URI', $_SERVER['PHP_SELF']);
# Define the current admin version
define('ADMIN_VERSION', '1.4.15');
# Start buffering
ob_start();
# Set up equivalents to glype's /includes/init.php constants
# that might be available in the settings file
define('GLYPE_URL', pathToURL(dirname(ADMIN_GLYPE_SETTINGS) . '/..'));
define('GLYPE_ROOT', str_replace('\\', '/', dirname(dirname(realpath(ADMIN_GLYPE_SETTINGS)))));
# And backwards compatibility (will be removed at some point)
function findURL() { return GLYPE_URL; }
define('LCNSE_KEY', '');
define('proxyPATH', GLYPE_ROOT . '/');
# Load current settings
$settingsLoaded = file_exists(ADMIN_GLYPE_SETTINGS) && (@include ADMIN_GLYPE_SETTINGS);
# Extract the "action" from the query string
$action = isset($_SERVER['QUERY_STRING']) && preg_match('#^([a-z-]+)#', $_SERVER['QUERY_STRING'], $tmp) ? $tmp[1] : '';
$cache_bust=filemtime(__FILE__)+filemtime(ADMIN_GLYPE_SETTINGS);
# SHORTCUTS
# Make a newline
define('NL', "\r\n");
/*****************************************************************
* IMAGES (ugly but keeps it in a single file)
******************************************************************/
if ( isset($_GET['image']) ) {
# Send image function
function sendImage($str) {
header('Content-Type: image/gif');
header('Last-Modified: ' . gmdate("D, d M Y H:i:s", filemtime(__FILE__)) . 'GMT');
header('Expires: ' . gmdate("D, d M Y H:i:s", filemtime(__FILE__) + (60*60)) . 'GMT');
echo base64_decode($str);
exit;
}
switch ( $_GET['image'] ) {
case 'bg.gif':
sendImage('R0lGODlhkAMMAMQAAP////7+/v3+/fz9/Pr7+vn6+fj6+Pj5+PX39fL08u/x7+ru6ubq5uDm4OHm4dzi3Njf2NTc1NHZ0c7XzsnTycfRxwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAACQAwwAAAX/4CACZGmeaKoC4oEkysI0DxRJU1WsfO//wKBwSCwaj8ikcslsOp/QqHRKrVqv2KxWWKBIIpCHg7FQJBAGwwgrWldbr9isdsvttvi8fs/v+/+AgYKDhIWGSV1fYWNlZ2luVm0DV3AwMjQ2ODqHnJ2en6ChoqOkpaaAiWBiZGZoapNsbZQDLpZzmXanuru8vb6/wMHCo6mLrI6vWZKztXKYdZvD0tPU1dbX2NmCxauNrpBvspG0cZd0mnfa6uvs7e7v8KTcjK2PsLPgUpXO57nx/wADChxIsGCJece+3RuXL8o+c7iiGZxIsaLFixj/IPRmT5m4cM0gQkuXsaTJkyhTO6bcWC9ZrIZQHt4aqbKmzZs4c1ZjiQymw49UZD5Dp7Oo0aNIk/bhqdCjTydC+0lUSrWq1atYVTDtyCYEADs=');
break;
case 'bullet_green.gif':
sendImage('R0lGODlhEAAQAMQAAFOYS////6LUoJW4kI/Bi+nv6F28V5TSlLTcs5TMkYTKgp3VmlelUJvKluv26r/hv4zOhJ/cnJnMmV7CWev461WcTaPUoZa6kZrWlr3etYrMiQAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAQABAAAAUzYCCOZGmeaKqu7ElF07Q4aoQ9TyKp03NoFobKgNAoJBXVIiGQEC4qR6MCGBRa2Kx2qwoBADs=');
break;
case 'bullet_grey.gif':
sendImage('R0lGODlhEAAQALMAAHR0dLW1te/v76Wlpby8vI2NjcfHx62trXp6eszMzP///wAAAAAAAAAAAAAAAAAAACH5BAEHAAoALAAAAAAQABAAAAQtUMlJq704682vIEURCBoRJMkRaEUSDATCGscQAFpwmMOgCQcAYEDqGI/IZCYCADs=');
break;
case 'button.gif':
sendImage('R0lGODlhCgAoAKIAAOno6Ovq6/f39////+vp6vPx8uzr6u/v7yH5BAAHAP8ALAAAAAAKACgAAAMtOLos/jDKSWssOOvNOz5gKI6jYZ5oqq4m4b4EIM90bd94ru987//AoHBILBoTADs=');
break;
case 'content_bg.gif':
sendImage('R0lGODlhCAAyALMAAP////v9/fj7+/X6+vH4+O729ur09Ofy8uPw8N/v79zt7djr6wAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAIADIAAAQ8EMgpl7046827/5oijmJiniairurhvq4hz3Jh3zah7/rg/z6BcCgMGI9GinLJbDqf0Kh0Sq1ar9islhoBADs=');
break;
case 'footer.gif':
sendImage('R0lGODlhkAMwAOYAAP////7+/v39/f3+/fz9/Pz8/Pv7+/v8+/r7+vn6+fj6+Pf59/j5+Pb49vf49/b39vX39fT29PL18vP18/L08vH08fHz8e/y7/Dy8O7x7u/x7+3w7e3x7ezv7Ovv6+vu6+ru6unt6ejs6Ofr5+br5ubq5uTp5OTo5OPo4+Hn4eLn4uDm4OHm4d/l397k3t3j3dvi29zi3Nvh29rh2tng2drg2tjf2Nnf2dfe19ff19bd1tbe1tXd1dXc1dTc1NPb09La0tDZ0NHZ0c/Yz87Xzs3WzczWzMzVzMrUysvUy8nTycrTysjSyMnSycfRxwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAACQAzAAAAf/gASCAISFhoeIiYoAggwQFBogJSsxNj5CRE4Ji5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubqiCUpCPjYxLCUgGhQQCgqDuILLtY2PkZOVl5mbu9jZ2tvc3d7f4OHi4+Tl5qm9v8HDxcfJzrbNBLfQkJKUlpia5/z9/v8AAwocSLCgQXDpgAkjZgyZsnnMmtEj4MjetHzWDmrcyLGjx48gQ4ocmHAdQ3cPc8mbWFEavmr7RsqcSbOmzZs4c4orubCdQ3jPJMajGO0eNX3XdCpdyrSp06dQCfJk1/AdxIlAZdVzeTRj1K9gw4odS7Zsoaknf14dmjXWVqMY/2OanUu3rt27eL+h9WlVpdCgLeHCTJq3sOHDiBMn3ls1ZcS2sN5eHKy4suXLmDPXZIwSstu/tCS/RKq5tOnTqFN346zWr2dXorvKVU27tu3buBWx7vt47azYcQnnHk68uPG8ux1j9a2VqMXRXo9Ln069us7kr1+tHBp4Mmnr4MOLHy8QO/PfoNF3hz6bvPv38OPbMu/6fGTnXIPL38+/v/9Q9PXGUlHeRfffgQgm6F6Ayw34nGzCKSjhhBTexiBb9mmHn2DfVejhhyBedmFQ2bECHGUhpqjiinONGFp6za0HIYs01mjjUi6iV+IqJ3Z4449ABrlRjs3tqEqPBgqp5P+STJJD5GdGpoJke01WaeWVtzx5X5SoTBkhlmCGKaYpWmrI5SlejqnmmmxyUiZsMH4mo35t1mnnmG+2sh1gBLL35Z2ABvpjnibGed+cKAqq6KI0EsqjoRoi6iOjlFY6oaNHQgqnpEla6umn+2EqpaZ6blgglaCmqip4onZJaqGcorrqrLQO1yqarz4a65+19urrabeasueLu/5q7LGmBVvKsOr12RURSCDBxLROVGvttdhmq+223Hbr7bfghivuuOSWa+656Kar7rrstuvuu/DGK++89NZr77345quvt9P2e8QR6sSwQlq8NcgdBBJo8EEJLLxwAw9ADDFEEhRT3O//xRhnrPHGHHfs8ccghyzyyCSXbPLJKKes8sost+zyyzDHLPPMNNds880456xzyRQPAQQPN7zAAgkfXCABBAwwcKarSy9LQDISXODBCCq8QIMOPwQRhBFcG7HE12CHLfbYZJdt9tlop6322my37fbbcMct99x012333XjnrffefPft99+ABy744IS7TYQQQuhAwwsqjOCB0Q88YIABAdSHy+QNTIBBByKg4IIMNvQABBBEEPHv6ainrvrqrLfu+uuwxy777LTXbvvtuOeu++689+7778AHL/zwxBdv/PHIJ6/88rhr3YMNMriAgggdYDBBAw1MXrmAtxxwAPYWbBCC/wkrWE2DDz5oXfr67Lfv/vvwxy///PTXb//9+Oev//789+///wAMoAAHSMACGvCACEygAhfIwAY68IH8Gx0OcPCCFZggBBuwQAQikIAECEAAluveARwQgQpkQBIqcIELaLCDHfzgB4iLoQxnSMMa2vCGOMyhDnfIwx768IdADKIQh0jEIhrxiEhMohKXyMQmOvGJUIyiFKdIxSoKsQc9oEEMYqACYmSgAhFwgAO8tz2D2cJ7C1hA1DwgAhOwwAUwgIENbMADHqDvjnjMox73yMc++vGPgAykIAdJyEIa8pCITKQiF8nIRjrykZCMpCQnSclKWvKSmMykJjd5yDlukf8FJhDB446WNDKG0BYFKEDSJjAB8ZGABG/8nAxAN8cc2PKWuMylLnfJy1768pfADKYwh0nMYhrzmMhMpjKXycxmOvOZ0IymNKdJzWpa85rYzKY2t/nLOXozji5gwQlOgEELWCByCEDAB08ZlA4+4gIdCEEJSqACFbTgnlvMpz73yc9++vOfAA2oQAdK0IIa9KAITahCF8rQhjr0oRCNqEQnStGKWvSiGM2oRjfK0Y4q9J71LEEIOmA0CECgg6ksADtr4b2klbAC8ZRnCVBAU5qu4KY4zalOd8rTnvr0p0ANqlCHStSiGvWoSE2qUpfK1KY69alQjapUp0rVqlr1qli4zapWt8pVo9J0niPVgAY2WMoDBKCMGMpFKjv4AFZeQGoeYKMI5jrPutr1rnjNq173yte++vWvgA2sYAdL2MIa9rCITaxiF8vYxjr2sZCNrGQnS9nKWvaymM2sYUPAWQ5wwJyRQ2kqdcEslraUARs0ZwZWG1cPgOC1sI2tbGdL29ra9ra4za1ud8vb3vr2t8ANrnCHS9ziGve4yE2ucpfL3OY697nQja50p0td4G7guuYka1nNStpAAAA7');
break;
case 'footer_bg.gif':
sendImage('R0lGODlhMgAyAMQAAIXDKYTCKYPAKIPBKIK/KIG+KIG9KIC8J4C7J3+6J3+5J364Jn23Jn22Jny1JXu0JXqzJXmyJHmxJHevJHiwJHauIwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAyADIAAAX/ICCOZGmeaKqubOu+cCzPdG3feK7vfO//wKCwFCgaj8ikcslsOp9Q5mBKrVqv2KzWKuh6v+CweEwum89oMmHNbrvf8Lh8Tq/b5YW8fs/v+/+AgYKDhIAGh4iJiouMjY6KB5GSk5SVlpeYmZqbnJgIn6ChoqOkpaanqKmqpgmtrq+wsbKztLAKt7i5uru8vb6/wMHCvgvFxsfIycrLzM3Oz9DMDNPU1dbX2Nna29zd3toN4eLj5OXm5+jkDuvs7e7v8PHy8/T19vIP+fr7/P3+/wADChxIsKDBgwUhKFzIsKHDhxAjSpxIsWLECBgzatzIsaPHjxsliBxJsqTJkyhTNKpcybJlSgowY8qcSbOmzZs4c+rceXOCz59AgwodSrSo0aNIkxatwLSp06dQo0qd+nTIixAAOw==');
break;
case 'nane.gif':
sendImage('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');
break;
case 'tableheader-bg-grey.gif':
sendImage('R0lGODlhqgsyAKIAAPHx8e/v7+3t7ezs7Orq6unp6ejo6Ofn5yH5BAAHAP8ALAAAAACqCzIAAAP/CLrc/jDKSau9OOvNu/9gKI5kaZ5oqq5s675wLM90bd94ru987//AoHBILBqPyKRyyWw6n9CodEolBq7YrHbL7Xq/4LB4TC6bz+i0es1uu9/wuHxOr9vv+Lx+z+/7/4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGRAqSlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7t4D8fLz9PX29/j5+vv8/f7/AAMKHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mix/6PHjyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bNmzhz6ty5koDPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtarVq1izat3KtavXr2DDih1LtqzZs2jTql3Ltq3bt3Djyp1Lt67du3jz6t3Lt6/fv4ADCx5MuLDhw4jxFljMuLHjx5AjS55MubLly5gza97MubPnz6BDix5NurTp06hTq17NurXr17Bjy55Nu7bt27hz697Nu7fv38CDCx9OvLjx48iTK1/OvLnz59CjS59OvXpxA9iza9/Ovbv37+DDix9Pvrz58+jTq1/Pvr379/Djy59Pv779+/jz69/Pv7////8ABijggAQWaOCBCCao4IIMNujggxBGKOGEFFZo4YUYZqjhhhx26OGHIIYo4ogklmjiiSimqOKKLLbo4oswxijjjDTWaOONOOao44489ujjj0AGKSSLBxRp5JFIJqnkkkw26eSTUEYp5ZRUVmnllVhmqeWWXHbp5ZdghinmmGSWaeaZaKap5ppstunmm3DGKeecdNZp55145qnnnnz26eefgAYq6KCEFmrooYgmquiijDbq6KOQRirppJRWaumlmGaq6aacdurpp6CGKuqopJZq6qmopqrqqqy26uqrsMYq66y01mrrrbjmquuuvPbq66/ABivssMQWa+yxyCar7LL/zDbr7LPQRivttNRWa+212Gar7bbcduvtt+CGK+645JZr7rnopqvuuuy26+678MYr77z01mvvvfjmq+++/Pbr778AByzwwAQXbPDBCCes8MIMN+zwwxBHLPHEFFds8cUYZ6zxxhx37PHHIIcs8sgkl2zyySinrPLKLLfs8sswxyzzzDTXbPPNOOes88489+zzz0AHLfTQRBdt9NFIJ6300kw37fTTUEct9dRUV2311VhnrfXWXHft9ddghy322GSXbfbZaKet9tpst+3223DHLffcdNdt991456333nz37fffgAcu+OCEF2744YgnrvjijDfu+OOQRy755JRXbvnl0phnrvnmnHfu+eeghy766KSXbvrpqKeu+uqst+7667DHLvvstNdu++2456777rz37vvvwAcv/PDEF2/88cgnr/zyzDfv/PPQRy/99NRXb/312Gev/fbcd+/99+CHL/745Jdv/vnop6/++uy37/778Mcv//z012///fjnr//+/Pfv//8ADKAAB0jAAhrwgAhMoAIXyMAGOvCBEIygBCdIwQpa8IIYzKAGN8jBDnrwgyAMoQhHSMISmvCEKEyhClfIwha68IUwjKEMZ0jDGtrwhuVKAAA7');
break;
case 'tableheader-bg.gif':
sendImage('R0lGODlhrgsyALMAAOPs8urw9O3y9eHr8t/q8t7q8uXt8+fu8+Xu8+ju8+fu9N7p8t3p8tzp8gAAAAAAACH5BAAAAAAALAAAAACuCzIAAAT/UMhJq7046827/2AojmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEgsGo/IpHLJbDqf0Kh0Sq1ar9isdsuFBr7gsHhMLpvP6LR6zW673/C4fE6v2+/4vH7P7/v/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipnQcHCaysCgqur7OwCQqts7WtsK+srrKuu7e+xbzFur+7r7i0xsfQxgm3zc6/vczT1tG+y7jCss+xyM7Vz8zHzbPqreHC69fa2gfh2/TE88PY5fLd5tIAj80rZm7ZtYPPpo3rZs1csG0GEfYCF3EhRHrnCKY7yO6WsFzY/96BvMcw27dkDck9HPaPnEtdFUu65NaN2kx42WrpPOeNl0dx/3a2FLexKEWfOEXOqydR1kmJOPl9pDXU3kGYRK0ijKjM4tZ993ZKlDmxXcWg5TL6+hay7U+RGJGOZBrN6Uh9caVGI5bRIMp+JO3ZzVcS7Up/av1ejakVGtdcXh2Dffg1ocajxiILVYsuqVt3c+PBpbtrMEqOKgH/qjpWoLKsrSXztCkzatiLltf6pMsM7TXWuj3HPTpa9Fy8tp7uBcvrMNXEAbFmJos7IW3cDgeKDdjZLNCbedWyHf7541LjS5HfU47XsOp20F++nt54u7TrlbNv59oTM0HfzXFWFv955L0VmlzpkWUaVMwB8x5fPEX32jrqLbhceM09CJxiAjEWm33I4CebftXNVNZPmQEIjIAYCdcRaOchSKGC+JxWlF4sxVeSdBrV11hXKk6m3Y/9eZcieMB1R+CL5nkmz4yC1cgghg5OtZqO1vCom4+xAQleeJTJxt2JvMESZJIDslMgjE6OVqGUF7pnJXx9SThSjx/+CFmQYA7ZZZEo/ocki+OpyaRcBbpJI3uFpTYnhLnt+JoBlFKKgKWYVmrApZp2Wimnm4Ka6aaZImAqqaKO6mmoo6aqqauncirqpa6Sumqnp75q66eyyvopq7jeamuqpvoq7K+51prrrckGe2z/q8T+Omysu0rLrLHVOvsqrapy62mt30ZLbK+tAqsrs6qGiu2xtK7LK7vugqvtsuVOyy2s8Na7KqzezpptutcGO66l2Lb7rbDxNvssqu4SnG+28p5rbr293nswwgUjHO6wuiq78MSo4krurgZre/G4De8LrLIRK2wtu+9KbGyxIZu8cczRLgwqvSSXSi2+GOt78bYcI6uyzuKK7HDPPP8rLcoAq+wy0UFD/PHOORdNs7cS75sxukqvy3XXVRtNtcslk30u1E4fPHXMAVutM9wUE2yxzUr3DDbRYjsdMd0145xx0/ImnLLbKTd9Nt5Hg7yzz3ervXjUAFNb7dgvl43p/8ArIwv00Wz/vXniLcd7NeCP2xt45nkvnTXMS1s7889Dey003pb76zHSAueNNshtF83r4QKT/vDrGsdet7qrU+4666zn3nHjD5steLmEJx/66W8rfzPye/OcesXNB9+58/wKX775qEM88uPZg7393N0DPzn0Q4v/tN3ll3672tKznuRuJsCVDe5zJxMZ8TpmvKqBr3H6KxX/MGe+XAHgghjMoAY3yMEOevCDIAyhCEdIwhKa8IQoTKEKV8jCFrrwhTCMoQxnSMMa2vCGOMyhDnfIwx768IdADKIQh0jEIhrxiEhMohKXyMQmOvGJUIyiFKdIxSpa8YpYzKIWt8jFLv968YtgDGMVB0DGMprxjGhMoxrXyMY2uvGNcIyjHOdIxzra8Y54zKMe98jHPvrxj4AMpCAHSchCGvKQiEykIhfJyEY68pGQjKQkJ0nJSlrykpjMpCY3yclOevKToAylKEdJylKa8pSoTKUqV8nKVrpSlASIpSxnScta2vKWuMylLnfJy1768pfADKYwZ1mAYRrzmMhMpjKXycxm8rKYzoymNKdJzWpak5jXzKY2t8nNbUKzm+AMpzjHSc5ufrOc6EynOqd5znW6853w9GU740nPetJznvbMpz73qU988vOfAKWmPwNK0IIic6AGTahCn7lQcRagAAt4qEQjKlGIVvT/ohjNKEUzytGOatSjIA2pSEdK0pJydKMbNelEU2pRlYaUpSw1aUxdelKa2vSmOBUpSnG6AJjm9KMVnSlJhfpTov70qEh96UR56tOkPrSpNDUqT51K1ap2dKc37elFpRrVrWbVqi29qldtylWygvWsVsUqWaGaVLaqtKxdRatckarWqLr1qHctKVxdute5+lWsT2XqWJ2a16GCta9/TWxQl5rVwk51sWZNK0gdq9PDKvayemXsWgfbVs6+1bKYDe1kNWtXz+LVtJmVrGhXC9SwlhayhEWtYVXL2toG9rabhW1ndftZ2l6UAcANrnCHS9ziGve4yE2ucpfL3OY697nQ/42udKdL3epa97rYza52t8vd7nr3u+ANr3jHS97ymve86E2vetfL3va6973wja9850vf+tr3vvjNr373y9/++ve/AA6wgAdM4AIb+MAITrCC/duABjv4wRCOsIQnTOEKW/jCGM6whjfM4Q57+MMgDrGIR0ziEpv4xChOsYpXzOIWu/jFMI6xjGdM4xrb+MY4zrGOd8zjHvv4x0AOspCHTOQiG/nISE6ykpfM5CY7+clQjrKUp0zlKlv5yktecHcbUFwui9fLWg6zdcEsXDJ/18xiTvNz0cwANnPXzWqOM3LZDGft1lnOeA4zncd75zznec9f9rOgjQvo8PZ50GouNP94D43oRjO4y3x2dKMVfWZJI5rS3mW0pROM6S1vWr9YDrWoR03qUpv61KhOtapXzepWu/rVsI61rGdN61rb+ta4zrWud83rXvv618AOtrCHTexiG/vYyE62spfN7GY7+9nQjra0p03talv72tjOtra3ze1ue/vb4A63uMdN7nKb+9zoTre6183udrv73fCOt7znTe962/ve+M63vvfN7377+98AD7jAB07wghv84AhPuMIXzvCGO/zhEI+4xCdO8Ypb/OIYz7jGN87xjnv84yAPuchHTvKSm/zkKE+5ylfO8pa7/OUwj7nMZ07zmtv85jjPuc53zvOe+/znQA+60If/TvSiG/3oSE+60pfO9KY7/elQj7rUp071qlv96ljPuta3zvWue/3rYA+72MdO9rKb/exoT7va1872trv97XCPu9znTve62/3ueM+73vfO9777/e+AD7zgB0/4whv+8IhPvOIXz/jGO/7xkI+85CdP+cpb/vKYz7zmN8/5znv+86APvehHT/rSm/70qE+96lfP+ta7/vWwj73sZ0/72tv+9rjPve53z/ve+/73wA++8IdP/OIb//jIT77yl8/85jv/+dCPvvSnT/3qW//62M++9rfP/e57//vgD7/4x0/+8pv//OhPv/rXz/72u//98I+//OdP//rb//74z7/+98//Yf77//8AGIACOIAEWIAGeIAImIAKuIAM2IAO+IAQGIESOIEUWIEWeIEYmIEauIEc2IEe+IEgGIIiOIIkWIImeIIomIIquIIs2IIu+IIwGIMyOIM0WIM2eIM4mIM6uIMvFwEAOw==');
break;
case 'top_left.gif':
sendImage('R0lGODlhCgAyAMQAAKvWa5rNTYjFL4XDKYTCKYTBKIPBKIPAKIK/KIG+J4G+KIC9J4C8J3+7J366Jn66J365Jn24Jny2Jnu2Jny3Jnu1JXq0JQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAHAP8ALAAAAAAKADIAAAV/ICCOZFkGaKoKbOsScCwbdG0jeK4nfO8zwKCwQSwaH8ikMsJsOinQqHRCrVot2Kx2u614v+BwWEIum89nqXqtdrrf8DhkTq877vi8cc/fC/+AfwuDhIWGhgqJiouMjDqPkJGSB5SVlpeXBZqbnJ2dMqChoAOkpaanqKmqq6ynIQA7');
break;
case 'loading.gif':
sendImage('R0lGODlhEAAQAPIAAP///2ZmZtra2o2NjWZmZqCgoLOzs729vSH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==');
break;
}
}
/*****************************************************************
* FUNCTIONS
******************************************************************/
# Quote string
function quote($str) {
$str = str_replace('\\', '\\\\', $str);
$str = str_replace("'", "\'", $str);
return "'$str'";
}
# Convert filesize from bytes to most suitable unit
function formatSize($bytes) {
# Define suitable units in 1024x increments
$types = array( 'B', 'KB', 'MB', 'GB', 'TB' );
# Decrease until we run out of units or we're less than 1024 in the current unit
for ( $i = 0, $l = count($types)-1; $bytes >= 1024 && $i < $l; $bytes /= 1024, $i++ );
# Return a rounded figure with unit
return ( round($bytes, 2) . ' ' . $types[$i] );
}
# Convert path to URL
function pathToURL($filePath) {
# Run through realpath to normalise path
$realPath = realpath($filePath);
# Verify that the path passed is real and find the directory
if ( is_file($realPath)) {
$dir = dirname($realPath);
} elseif ( is_dir($realPath) ) {
$dir = $realPath;
} else {
# Path does not exist, fails
return false;
}
# Expand the document root path
$_SERVER['DOCUMENT_ROOT'] = realpath($_SERVER['DOCUMENT_ROOT']);
# Make sure the path is not lower than the server root
if ( strlen($dir) < strlen($_SERVER['DOCUMENT_ROOT']) ) {
return false;
}
# Determine path from web root
$rootPos = strlen($_SERVER['DOCUMENT_ROOT']);
# Make sure $rootPos includes the first slash
if ( ( $tmp = substr($_SERVER['DOCUMENT_ROOT'], -1) ) && ( $tmp == '/' || $tmp == '\\' ) ) {
--$rootPos;
}
# Extract path below webroot and discard path above webroot
$pathFromRoot = substr($realPath, $rootPos);
# Build URL from parts
$path = 'http' . ( isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off' ? 's' : '' ) . '://' . $_SERVER['HTTP_HOST'] . $pathFromRoot;
# Convert to forward slash if on Windows
if ( DIRECTORY_SEPARATOR == '\\' ) {
$path = str_replace('\\', '/', $path);
}
return $path;
}
# Hide from non-js browsers by using document.write() to output
function jsWrite($str) {
return '<script type="text/javascript">document.write(' . quote($str) . ');</script>';
}
# Convert a string of bool value to bool
function bool($str) {
if ( $str == 'false' ) {
return false;
}
if ( $str == 'true' ) {
return true;
}
return NULL;
}
/*****************************************************************
* CLASSES
******************************************************************/
/*****************************************************************
* Location wrapper - allows us to have observers on the location
******************************************************************/
class Location {
# Observers
private $observers;
# Redirect elsewhere
public function redirect($to = '') {
# Notify observers
$this->notifyObservers('redirect');
# Redirect and quit
header('Location: ' . ADMIN_URI . '?' . $to);
exit;
}
# Redirect elsewhere but without observer
public function cleanRedirect($to = '') {
# Redirect and quit
header('Location: ' . ADMIN_URI . '?' . $to);
exit;
}
# Register observers
public function addObserver(&$obj) {
$this->observers[] = $obj;
}
# Notify observers
public function notifyObservers($action) {
# Determine method to call
$method = 'on' . ucfirst($action);
# Prepare parameters
$params = func_get_args();
array_shift($params);
# Loop through all observers
foreach ( $this->observers as $obj ) {
# If an observing method exists, call it
if ( method_exists($obj, $method) ) {
call_user_func_array(array(&$obj, $method), $params);
}
}
}
}
/*****************************************************************
* Input wrapper for incoming data
******************************************************************/
class Input {
# Set up inputs
public function __construct() {
$this->GET = $this->prepare($_GET);
$this->POST = $this->prepare($_POST);
$this->COOKIE = $this->prepare($_COOKIE);
}
# Return array with keys converted to lowercase and values cleaned
private function prepare($array) {
$return = array();
foreach ( $array as $key => $value ) {
$return[strtolower($key)] = self::clean($value);
}
return $return;
}
# Get an input - inputs can be requested in the form pVarName
# where VarName is (case insensitive) name of variable (duh!)
# and p denotes from _POST. G and C are also available.
public function __get($name) {
# Do we have a varname?
if ( ! isset($name[1]) ) {
return NULL;
}
# Split into GPC and VarName (case insensitive)
$from = strtolower($name[0]);
$var = strtolower(substr($name, 1));
# Define $from to target relationships
$targets = array('g' => $this->GET,
'p' => $this->POST,
'c' => $this->COOKIE);
# Look for the value and return it
if ( isset($targets[$from][$var]) ) {
return $targets[$from][$var];
}
# Not found, return false
return NULL;
}
# Clean a value
static public function clean($val) {
static $magicQuotes;
# What is our magic quotes setting?
if ( ! isset($magicQuotes) ) {
$magicQuotes = get_magic_quotes_gpc();
}
# What type is this?
switch ( true ) {
case is_string($val):
# Strip slashes and trim
if ( $magicQuotes ) {
$val = stripslashes($val);
}
$val = trim($val);
break;
case is_array($val):
$val = array_map(array('Input', 'clean'), $val);
break;
default:
return $val;
}
return $val;
}
}
/*****************************************************************
* Output wrappers
******************************************************************/
# A simple overloading object
class Overloader {
# Store variables in this array
protected $data;
# Set value (case insensitive)
public function __set($name, $value) {
$this->data[strtolower($name)] = $value;
}
# Get value (case insensitive)
public function __get($name) {
$name = strtolower($name);
return isset($this->data[$name]) ? $this->data[$name] : '';
}
}
# Base wrapper object
abstract class Output extends Overloader {
# Full page to output
protected $output;
# Content only
protected $content;
# Array of observers
protected $observers = array();
# Output the page
final public function out() {
# Notify our observers we're about to print
$this->notifyObservers('print', $this);
# Wrap content in our wrapper
$this->wrap();
# Send headers
$this->sendHeaders();
# Send body
print $this->output;
# Page completed, finish
exit;
}
# Override this to send custom headers instead of default (html)
protected function sendHeaders() {}
# Wrapper for body content
protected function wrap() {
$this->output = $this->content;
}
# Add content
public function addContent($content) {
$this->content .= $content;
}
# Register observers
public function addObserver(&$obj) {
$this->observers[] = $obj;
}
# Notify observers
public function notifyObservers($action) {
# Determine method to call
$method = 'on' . ucfirst($action);
# Prepare parameters
$params = func_get_args();
array_shift($params);
# Loop through all observers
foreach ( $this->observers as $obj ) {
# If an observing method exists, call it
if ( method_exists($obj, $method) ) {
call_user_func_array(array(&$obj, $method), $params);
}
}
}
# Send status code
public function sendStatus($code) {
header(' ', true, $code);
}
# More overloading. Set value with key.
public function __call($func, $args) {
if ( substr($func, 0, 3) == 'add' && strlen($func) > 3 && ! isset($args[2]) ) {
# Saving with key or not?
if ( isset($args[1]) ) {
$this->data[strtolower(substr($func, 3))][$args[0]] = $args[1];
} else {
$this->data[strtolower(substr($func, 3))][] = $args[0];
}
}
}
}
# Output with our HTML skin
class SkinOutput extends Output {
# Print all
private function printAll($name) {
$name = strtolower($name);
if ( isset($this->data[$name]) && is_array($this->data[$name]) ) {
foreach ( $this->data[$name] as $item ) {
echo $item;
}
}
}
# Wrap content in HTML skin
protected function wrap() {
# Prepare the "get image" path
$imgs = ADMIN_URI . '?image=';
# Self
$self = ADMIN_URI;
# Prepare date
$date = date('H:i, d F Y');
# Append "glype control panel" to title
$title = $this->title . ( $this->title ? ' : ' : '' ) . 'Glype 代理服务后台';
# Buffer so we can get this into a variable
ob_start();
# Print output
echo <<<OUT
<!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>
<title>{$title}</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript">var offsetx=12;var offsety=8;function newelement(a){if(document.createElement){var b=document.createElement('div');b.id=a;with(b.style){display='none';position='absolute'}b.innerHTML='&nbsp;';document.body.appendChild(b)}}var ie5=(document.getElementById&&document.all);var ns6=(document.getElementById&&!document.all);var ua=navigator.userAgent.toLowerCase();var isapple=(ua.indexOf('applewebkit')!=-1?1:0);function getmouseposition(e){if(document.getElementById){var a=(document.compatMode&&document.compatMode!='BackCompat')?document.documentElement:document.body;pagex=(isapple==1?0:(ie5)?a.scrollLeft:window.pageXOffset);pagey=(isapple==1?0:(ie5)?a.scrollTop:window.pageYOffset);mousex=(ie5)?event.x:(ns6)?clientX=e.clientX:false;mousey=(ie5)?event.y:(ns6)?clientY=e.clientY:false;var b=document.getElementById('tooltip');b.style.left=(mousex+pagex+offsetx)+'px';b.style.top=(mousey+pagey+offsety)+'px'}}function tooltip(a){if(!document.getElementById('tooltip'))newelement('tooltip');var b=document.getElementById('tooltip');b.innerHTML=a;b.style.display='block';document.onmousemove=getmouseposition}function exit(){document.getElementById('tooltip').style.display='none'}window.domReadyFuncs=new Array();window.addDomReadyFunc=function(a){window.domReadyFuncs.push(a)};function init(){if(arguments.callee.done)return;arguments.callee.done=true;if(_timer)clearInterval(_timer);for(var i=0;i<window.domReadyFuncs.length;++i){try{window.domReadyFuncs[i]()}catch(ignore){}}};if(document.addEventListener){document.addEventListener("DOMContentLoaded",init,false)}/*@cc_on@*//*@if(@_win32)document.write("<script id=__ie_onload defer src=javascript:void(0)><\\\/script>");var script=document.getElementById("__ie_onload");script.onreadystatechange=function(){if(this.readyState=="complete"){init()}};/*@end@*/if(/WebKit/i.test(navigator.userAgent)){var _timer=setInterval(function(){if(/loaded|complete/.test(document.readyState)){init()}},10)}window.onload=init;if(!window.XMLHttpRequest){window.XMLHttpRequest=function(){return new ActiveXObject('Microsoft.XMLHTTP')}}function runAjax(a,b,c,d){var e=new XMLHttpRequest();var f=b?'POST':'GET';e.open(f,a,true);e.setRequestHeader("Content-Type","application/x-javascript;");e.onreadystatechange=function(){if(e.readyState==4&&e.status==200){if(e.responseText){c.call(d,e.responseText)}}};e.send(b)}</script>
<script type="text/javascript">
OUT;
# Add domReady javascript
if ( $this->domReady ) {
echo 'window.addDomReadyFunc(function(){', $this->printAll('domReady'), '});';
}
# Add other javascript
if ( $this->javascript ) {
echo $this->printAll('javascript');
}
echo <<<OUT
</script>
<style type="text/css">body{margin:0;font-size:62.5%;font-family:Verdana, Arial, Helvetica, sans-serif;padding:15px 0;background:#eee}#wrap{width:820px;margin:0 auto;background:url({$self}?image=bg.gif) top center repeat-y #FFF}#top_content{padding:0 10px}#topheader{padding:25px 15px 15px;margin:0 auto;background:url({$self}?image=top_left.gif) top left repeat-x #85C329}#rightheader{float:right;width:375px;height:40px;color:#FFF;text-align:right}#rightheader p{padding:35px 15px 0 0;margin:0;text-align:right}#title{padding:0;margin:0;font-size:2.5em;color:#FFF}#title span{font-size:0.5em;font-style:italic}#title a:link,#title a:visited{color:#FFF;text-decoration:none}#title a:hover{color:#E1F3C7}#navigation{background:#74A8F5;border-top:1px solid #fff;height:25px;clear:both}#navigation ul{padding:0;margin:0;list-style:none;font-size:1.1em;height:25px}#navigation ul li{display:inline}#navigation ul li a{color:#FFF;display:block;text-decoration:none;float:left;line-height:25px;padding:0 16px;border-right:1px solid #fff}#navigation ul li a:hover{background:#5494F3}#content{padding:15px;margin:0 auto;background:url({$self}?image=content_bg.gif) repeat-x left top #fff;color:#666}#content h1,#content h2,#content h3,#content h4,#content h5{color:#74A8F5}#content h1{font-family:"Trebuchet MS", Arial, Helvetica;padding:0;margin:0 0 15px;font-size:2em}#content h2{font-family:"Trebuchet MS", Arial, Helvetica;padding:0;margin:0 0 15px;font-size:1.5em}#top_body,#content_body{padding:0 25px}#footer{background:url({$self}?image=footer.gif) no-repeat center bottom;color:#FFF;padding:0 10px 13px}#footer p a:link,#footer p a:visited{color:#FFF;font-style:italic;text-decoration:none}#footer #footer_bg{background:url({$self}?image=footer_bg.gif) repeat-x left bottom #85C329;padding:15px 15px 25px;border-top:1px solid #7BB425}#footer #design{display:block;width:150px;height:30px;float:right;line-height:20px;padding:0 5px;text-align:right;color:#E1F3C7}#footer #design a,#rightheader a:link,#rightheader a:visited{color:#FFF;text-decoration:underline}.table{margin-bottom:15px;width:100%;border-collapse:collapse}.table_header td a:link,.table_header td a:visited{text-decoration:underline;color:#467aa7}.table_header td{background:url({$self}?image=tableheader-bg.gif) no-repeat left top;padding:5px 10px;color:#467aa7;border-top:1px solid #CBD6DE;border-bottom:1px solid #ADBECB;font-size:1.1em;font-weight:bold;border:1px solid #CBD6DE}.row1 td,.row2 td,.row3 td,.row_hover td,.paging_row td{padding:5px 10px;color:#666;border:1px solid #CBD6DE}.row1 td{background:#fff}.row2 td{background:#f6f6f6}.row3 td{background:#eee}.row1:hover td,.row2:hover td,.row3:hover td{background:#FBFACE;color:#000}.hidden{display:none}#content .little{font-size:9px}.clear{clear:both}.img_left{float:left;padding:1px;border:1px solid #ccc;margin:0 10px 10px 0}#content ul{font-size:1.1em;line-height:1.8em;margin:0 0 15px;padding:0;list-style-type:none}#content p{font-size:1.2em;margin:0;padding:0 0 15px;line-height:150%}#content p a:hover,.table a:hover,.form_table a:hover,.link a:hover{text-decoration:underline}#content ul.green li{padding:0 0 0 20px;margin:0;background:url({$self}?image=bullet_green.gif) no-repeat 1px 3px;font-size:1.1em}#content ul.black li{padding:0 0 0 20px;margin:0;background:url({$self}?image=bullet_grey.gif) no-repeat 1px 3px;font-size:1.1em}#content ul.black li a:link,#content ul.black li a:visited{color:#666;text-decoration:none}#content ol{padding:0 0 0 25px;margin:0 0 15px;line-height:1.8em}#content ol li{font-size:1.1em}#content ol li a:link,#content ol li a:visited,#content ul.green li a:link,#content ul.green li a:visited,#content p a,#content p a:visited,.table a,.table a:visited,.form_table a,.link a{color:#73A822;text-decoration:none}#content ol li a:hover,#content ul.green li a:hover,.table_header td a:hover{color:#73A822;text-decoration:underline}#content p.paging{padding:5px;border:1px solid #CBD6DE;text-align:center;margin-bottom:15px;background:#eee}.small_input{font-size:10px}.form_table{margin-bottom:15px;font-size:1.1em}.form_table td{padding:5px 10px}input.button{margin:0;padding:2px;border:3px double #999;border-left-color:#ccc;border-top-color:#ccc;background:url({$self}?image=button.gif) repeat-x left top;font-size:11px;font-family:Verdana, Arial, Helvetica, sans-serif}input.inputgri,select.inputgri,textarea.inputgri{background:#eee;font-size:14px;border:1px solid #ccc;padding:3px}input.inputgri:focus,select.inputgri:focus,textarea.inputgri:focus{background:#fff;border:1px solid #686868}textarea.inputgri{font-size:12px;font-family:Verdana, Arial, Helvetica, sans-serif;height:60px}.notice{background:#CAEA99;border:1px solid #70A522;padding:15px;margin-bottom:15px;font-size:1.2em;color:#333}.notice_error{background:#FEDCDA;border:1px solid #CE090E;padding:15px;margin-bottom:15px;font-size:1.2em;color:#333}.notice .close,.notice_error .close{float:right;cursor:pointer;color:#fff;background:#74A8F5;padding:2px;margin-right:2px;border:1px outset #ccc}#notice a{color:#333;text-decoration:underline}.other_links{background:#eee;border-top:1px solid #ccc;padding:5px;margin:0 0 15px}#content .other_links h2{color:#999;padding:0 0 0 3px;margin:0}#content .other_links ul li{padding:0 0 0 20px;background:url({$self}?image=bullet_grey.gif) no-repeat left center}#content .other_links a,#content .other_links a:visited,#content ul.black li a:hover{color:#999;text-decoration:underline}#content .other_links a:hover{color:#666}code{font-size:1.2em;color:#73A822}#tooltip{width:20em;color:#fff;background:#555;font-size:12px;font-weight:normal;padding:5px;border:3px solid #333;text-align:left}.hr{border-top:2px solid #ccc;margin:5px 0 15px}.bold,#rightheader p span{font-weight:bold}.center{text-align:center}.right{text-align:right}.error-color{color:#CE090E}.ok-color{color:#70A522}.wide-input{width:350px}.small-input{width:50px}.tooltip{padding-bottom:1px;border-bottom:1px dotted #70A522;cursor:help}.ajax-loading{background:url({$self}?image=loading.gif)}.bar{background:#73A822;height:10px;font-size:xx-small;padding:2px;color:#000}.comment{padding:5px;border:1px solid #CBD6DE;border-width:1px 0 1px 0;margin-bottom:15px;background:#f6f6f6}#content .comment p,#content .comment ul,#content .other_links ul,form,.checkbox_nomargins,.form_table p,#footer p{margin:0;padding:0}#preload{position:absolute;height:10px;top:-100px}</style>
</head>
<body>
<div id="wrap">
<div id="top_content">
<div id="header">
<div id="rightheader">
<p>
{$date}
<br />
OUT;
# Add the "welcome" and log out link
if ( $this->admin ) {
echo "欢迎, <i>{$this->admin}</i> : <strong><a href=\"{$self}?logout\">退出</a></strong>\r\n";
}
$http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
echo <<<OUT
</p>
</div>
<div id="topheader">
<h1 id="title">
<a href="{$self}">Glype 管理面板</a><br>
<span>for {$http_host}</span>
</h1>
</div>
<div id="navigation">
<ul>
OUT;
# Add navigation
if ( is_array($this->navigation) ) {
foreach ( $this->navigation as $text => $href ) {
if (stripos($href,$self)!==false) {
echo "<li><a href=\"{$href}\">{$text}</a></li>\r\n";
} else {
echo "<li><a href=\"{$href}\" target=\"_blank\">{$text}</a></li>\r\n";
}
}
}
echo <<<OUT
</ul>
</div>
</div>
<div id="content">
<h1>{$this->bodyTitle}</h1>
OUT;
# Do we have any error messages?
if ( $this->error ) {
# Print all
foreach ( $this->error as $id => $message ) {
echo <<<OUT
<div class="notice_error" id="notice_error_{$id}">
<a class="close" title="Dismiss" onclick="document.getElementById('notice_error_{$id}').style.display='none';">X</a>
{$message}
</div>
OUT;
}
}
# Do we have any confirmation messages?
if ( $this->confirm ) {
# Print all
foreach ( $this->confirm as $id => $message ) {
echo <<<OUT
<div class="notice" id="notice_{$id}">
<a class="close" title="Dismiss" onclick="document.getElementById('notice_{$id}').style.display='none';">X</a>
{$message}
</div>
OUT;
}
}
# Print content
echo $this->content;
# Print footer links
if ( is_array($this->footerLinks) ) {
echo '
<br>
<div class="other_links">
<h2>也可以看看</h2>
<ul class="other">
';
foreach ( $this->footerLinks as $text => $href ) {
echo "<li><a href=\"{$href}\">{$text}</a></li>\r\n";
}
echo '
</ul>
</div>
';
}
# And finish off the page
echo <<<OUT
</div>
</div>
<div id="footer">
<div id="footer_bg">
<p><a href="http://www.glype.com/">Glype</a>&reg; &copy; 2007-2015 Glype. All rights reserved.</p>
</div>
</div>
</div>
<div id="preload">
<span class="ajax-loading">&nbsp;</span>
</div>
</body>
</html>
OUT;
$this->output = ob_get_contents();
# Discard buffer
ob_end_clean();
}
}
# Send output in "raw" form
class RawOutput extends Output {
protected function sendHeaders() {
header('Content-Type: text/plain; charset="utf-8"');
header('Content-Disposition: inline; filename=""');
}
}
/*****************************************************************
* User object
******************************************************************/
# Manage sessions and stores user data
class User {
# Username we're logged in as
public $name;
# Our user agent
public $userAgent;
# Our IP address
public $IP;
# Reason for aborting a session
public $aborted;
# Constructor sets up session
public function __construct() {
# Don't try to start if autostarted
if ( session_id() == '' ) {
# Set up new session
session_name('admin');
session_start();
}
# Always use a fresh ID for security
session_regenerate_id();
# Prepare user data
$this->userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
$this->IP = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
# Use user-agent and IP as identifying data since these shouldn't change mid-session
$authKey = $this->userAgent . $this->IP;
# Do we have a stored auth key?
if ( isset($_SESSION['auth_key']) ) {
# Compare our current auth_key to stored key
if ( $_SESSION['auth_key'] != $authKey ) {
# Mismatch. Session may be stolen.
$this->clear();
$this->aborted = 'Session data mismatch.';
}
} else {
# No stored auth key, save it
$_SESSION['auth_key'] = $authKey;
}
# Are we verified?
if ( ! empty($_SESSION['verified']) ) {
$this->name = $_SESSION['verified'];
}
# Have we expired? Only expire if we're logged in of course...
if ( $this->isAdmin() && isset($_SESSION['last_click']) && $_SESSION['last_click'] < (time() - ADMIN_TIMEOUT) ) {
$this->clear();
$this->aborted = 'Your session timed out after ' . round(ADMIN_TIMEOUT/60) . ' minutes of inactivity.';
}
# Set last click time
$_SESSION['last_click'] = time();
}
# Log out, destroy all session data
public function clear() {
# Clear existing
session_destroy();
# Unset existing variables
$_SESSION = array();
$this->name = false;
# Restart session
session_start();
}
# Log in, saving username session for future requests
public function login($name) {
$this->name = $name;
$_SESSION['verified'] = $name;
}
# Are we verified or not?
public function isAdmin() {
return (bool) $this->name;
}
}
/*****************************************************************
* Notice handler (errors or confirmations)
******************************************************************/
class Notice {
# Storage of messages
private $data = array();
# Type of notice handler
private $type;
# Constructor fetches any stored from session and clears session
public function __construct($type) {
# Save type
$this->type = $type;
# Array key
$key = 'notice_' . $type;
# Any existing?
if ( isset($_SESSION[$key]) ) {
# Extract
$this->data = $_SESSION[$key];
# And clear
unset($_SESSION[$key]);
}
}
# Get messages
public function get($id = false) {
# Requesting an individual message?
if ( $id !== false ) {
return isset($this->data[$id]) ? $this->data[$id] : false;
}
# Requesting all
return $this->data;
}
# Add message
public function add($msg, $id = false) {
# Add with or without an explicit key
if ( $id ) {
$this->data[$id] = $msg;
} else {
$this->data[] = $msg;
}
}
# Do we have any messages?
public function hasMsg() {
return ! empty($this->data);
}
# Observer the print method of output
public function onPrint($output) {
$funcName = 'add' . $this->type;
# Add our messages to the output object
foreach ( $this->data as $msg ) {
$output->{$funcName}($msg);
}
}
# Observe redirects - store notices in session
public function onRedirect() {
$_SESSION['notice_' . $this->type] = $this->data;
}
}
/*****************************************************************
* Initialize instances of defined classes. If we were structing
* this nicely we'd stick the above in separate files to keep it
* clean but we're sacrificing good structure for the convenience
* of running this admin script stand-alone.
******************************************************************/
# Create output object
$output = new SkinOutput;
# Create an overloader object to hold our template vars.
# This keeps them all together and avoids problems with undefined variable notices.
$tpl = new Overloader;
# Location wrapper for redirections
$location = new Location;
# Create user object
$user = new User();
# Create notice handlers
$confirm = new Notice('confirm');
$error = new Notice('error');
# Input wrapper
$input = new Input;
/*****************************************************************
* Nearly finished preparing, now just bind them together as appropriate
******************************************************************/
# Add notice handlers as observers of the output object
$output->addObserver($confirm);
$output->addObserver($error);
# Add notice handlers as observers on redirect();
$location->addObserver($confirm);
$location->addObserver($error);
# Pass user details to output object
$output->admin = $user->name;
/*****************************************************************
* AJAX INTERCEPTS
******************************************************************/
if ( $input->gFetch && $user->isAdmin() ) {
# Stop caching of response
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT' );
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
switch ( $input->gFetch ) {
# Get the latest news
case 'news':
# Style the news
echo '<style type="text/css">body { margin:0; padding:5px; font:80% Tahoma,Verdana; } a { color: #73A822; }</style>';
# Connect to glype
if ($ch=curl_init('http://www.glype.com/feeds/news.php?vn='.urlencode($CONFIG['version']).'&lk='.urlencode($CONFIG['license_key']).'&cb='.$cache_bust)) {
curl_setopt($ch, CURLOPT_TIMEOUT, 2);
$success = curl_exec($ch);
curl_close($ch);
}
# Ensure we have a return
if ( empty($success) ) {
echo '当前无法连接到glype.com进行新闻更新。';
}
break;
# Verify a directory exists and is writable
case 'test-dir':
$fail = false;
# Verify
if ( ! ( $dir = $input->gDir ) ) {
# Check we have a dir to test
$fail = 'no directory given';
} else if ( ! file_exists($dir) || ! is_dir($dir) ) {
# Check it exists and is actually a directory
$fail = 'directory does not exist';
# Try to create it (in case it was inside the temporary directory)
if ( ! bool($input->gTmp) && is_writable(dirname($dir)) && @mkdir($dir, 0755, true) ) {
# Reset error messages and delete directory
$fail = false;
$ok = '目录不存在,但是可以创建 ';
rmdir($dir);
}
} else if ( ! is_writable($dir) ) {
# Make sure it's writable
$fail = 'directory not writable - permission denied';
} else {
# OK
$ok = 'directory exists and is writable';
}
# Print result
if ( $fail ) {
echo '<span class="error-color">Error:</span> ', $fail;
} else {
echo '<span class="ok-color">OK:</span> ', $ok;
}
break;
}
# Finish here
exit;
}
/*****************************************************************
* Did our settings file load? If not, nothing else we can do.
******************************************************************/
if ( ! $settingsLoaded ) {
# Show error and exit
$error->add('The settings file for Glype could not be found.
Please upload this tool into your root glype directory.
If you wish to run this script from another location,
edit the configuration options at the top of the file.
<br><br>
Attempted to load: <b>' . ADMIN_GLYPE_SETTINGS . '</b>');
$output->out();
}
/*****************************************************************
* Verify a valid action and force to something else if not.
******************************************************************/
# Are we an admin? If not, force login page.
if ( ! $user->isAdmin() ) {
$action = 'login';
}
# Do we even have any user details? If not, force installer.
if ( ! isset($adminDetails) ) {
$action = 'install';
}
/*****************************************************************
* Prepare template variables
******************************************************************/
# URI to self
$self = ADMIN_URI;
# Links to other sections of the control panel
if ( $user->isAdmin() ) {
$output->addNavigation('主页', $self);
$output->addNavigation('编辑设置', $self.'?settings');
$output->addNavigation('查看日志', $self.'?logs');
$output->addNavigation('Glype&reg; 许可证', 'https://www.glype.com/purchase.php');
$output->addNavigation('BlockScript&reg;', $self.'?blockscript');
$output->addNavigation('支持论坛', 'http://proxy.org/forum/glype-proxy/');
$output->addNavigation('推广你的代理', 'https://proxy.org/advertise.shtml');
}
/*****************************************************************
* Process current request.
******************************************************************/
switch ( $action ) {
/*****************************************************************
* INSTALL - save an admin username/password in our settings file
******************************************************************/
case 'install':
# Do we have any admin details already?
if ( isset($adminDetails) ) {
# Add error
$error->add('An administrator account already exists. For security reasons, you must manually create additional administrator accounts.');
# And redirect to index
$location->redirect();
}
# Do we have any submitted details to process?
if ( $input->pSubmit ) {
# Verify inputs
if ( ! ( $username = $input->pAdminUsername ) ) {
$error->add('You must enter a username to protect access to your control panel!');
}
if ( ! ( $password = $input->pAdminPassword ) ) {
$error->add('You must enter a password to protect access to your control panel!');
}
# In case things go wrong, add this into the template
$tpl->username = $username;
# Process the installation if no errors
if ( ! $error->hasMsg() && is_writable(ADMIN_GLYPE_SETTINGS) ) {
# Load up the file
$file = file_get_contents(ADMIN_GLYPE_SETTINGS);
# Clear any closing php tag ? > (unnecessary and gets in the way)
if ( substr(trim($file), -2) == '?>
' ) {
$file = substr(trim($file), 0, -2);
}
# Look for a "Preserve Me" section
if ( strpos($file, '//---PRESERVE ME---') === false ) {
# If it doesn't exist, add it
$file .= "\r\n//---PRESERVE ME---
# Anything below this line will be preserved when the admin control panel rewrites
# the settings. Useful for storing settings that don't/can't be changed from the control panel\r\n";
}
# Prepare the inputs
$password = md5($password);
# Add to file
$file .= "\r\n\$adminDetails[" . quote($username) . "] = " . quote($password) . ";\r\n";
# Save updated file
if ( file_put_contents(ADMIN_GLYPE_SETTINGS, $file) ) {
# Add confirmation
$confirm->add('安装成功。您已将 <b>' . $username . '</b> 添加为管理员,并且现已登录。');
# Log in the installer
$user->login($username);
} else {
# Add error message
$error->add('Installation failed. The settings file appears writable but file_put_contents() failed.');
}
# Redirect
$location->redirect();
}
}
# Prepare skin variables
$output->title = 'install';
$output->bodyTitle = '初次使用安装';
# Add javascript
$output->addDomReady("document.getElementById('username').focus();");
# Is the settings file writable?
if ( ! ( $writable = is_writable(ADMIN_GLYPE_SETTINGS) ) ) {
$error->add('The settings file was found at <b>' . ADMIN_GLYPE_SETTINGS . '</b> but is not writable. Please set the appropriate permissions to make the settings file writable.');
# And disable the submit button
$tpl->disabled = ' disabled="disabled"';
} else {
$confirm->add('设置文件已找到并且可写。安装可以继续。. <b>不要在此阶段离开脚本!</b>');
}
# Print form
echo <<<OUT
<p>在设置文件中找不到管理员详细信息。在下面输入用户名和密码继续。将来所有尝试使用此控制面板的操作都将需要提供的详细信息。.</p>
<form action="{$self}?install" method="post">
<table class="form_table" border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="right">用户名:</td>
<td align="left"><input class="inputgri" id="username" name="adminUsername" type="text" value="{$tpl->username}"></td>
</tr>
<tr>
<td align="right">密码:</td>
<td align="left"><input class="inputgri" name="adminPassword" type="password"></td>
</tr>
</table>
<p><input class="button" value="提交 &raquo;" name="submit" type="submit"{$tpl->disabled}></p>
</form>
OUT;
break;
/*****************************************************************
* LOG IN
******************************************************************/
case 'login':
# Do we have any login details to process?
if ( $input->pLoginSubmit ) {
# Verify inputs
if ( ! ( $username = $input->pAdminUsername ) ) {
$error->add('You did not enter your username. Please try again.');
}
if ( ! ( $password = $input->pAdminPassword ) ) {
$error->add('You did not enter your password. Please try again.');
}
# Validate the submitted details
if ( ! $error->hasMsg() ) {
# Validate submitted password
if ( isset($adminDetails[$username]) && $adminDetails[$username] == md5($password) ) {
# Update user
$user->login($username);
# Redirect to index
$location->cleanRedirect();
} else {
# Incorrect password
$error->add('The login details you submitted were incorrect.');
}
}
}
# Have we been automatically logged out?
if ( $user->aborted ) {
$error->add($user->aborted);
}
# Set up page titles
$output->title = '登录';
$output->bodyTitle = '登录';
# Add javascript
$output->addDomReady("document.getElementById('username').focus();");
# Show form
echo <<<OUT
<p>在设置文件中找不到管理员详细信息。在下面输入用户名和密码继续。将来所有尝试使用此控制面板的操作都将需要提供的详细信息。..</p>
<form action="{$self}?login" method="post">
<table class="form_table" border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="right">用户名:</td>
<td align="left"><input class="inputgri" id="username" name="adminUsername" type="text"></td>
</tr>
<tr>
<td align="right">密码:</td>
<td align="left"><input class="inputgri" name="adminPassword" type="password"></td>
</tr>
</table>
<p><input class="button" value="提交 &raquo;" name="loginsubmit" type="submit"></p>
</form>
OUT;
break;
/*****************************************************************
* LOG OUT
******************************************************************/
case 'logout':
# Clear all user data
$user->clear();
# Print confirmation
$confirm->add('You are now logged out.');
# Redirect back to login page
$location->redirect('login');
break;
/*****************************************************************
* INDEX - check status and print summary
******************************************************************/
case '':
#
# System requirements
#
$requirements = array();
# PHP VERSION ----------------------
# Find PHP version - may be bundled OS so strip that out
$phpVersion = ( $tmp = strpos(PHP_VERSION, '-') ) ? substr(PHP_VERSION, 0, $tmp) : PHP_VERSION;
# Check above 5 and if not, add error text
if ( ! ( $ok = version_compare($phpVersion, '5', '>=') ) ) {
$error->add('Glype requires at least PHP 5 or greater.');
}
# Add to requirements
$requirements[] = array(
'name' => 'PHP version',
'value' => $phpVersion,
'ok' => $ok
);
# CURL -------------------------------
# Check for libcurl
if ( ! ( $ok = function_exists('curl_version') ) ) {
$error->add('Glype requires cURL/libcurl.');
}
# curl version
$curlVersion = $ok && ( $tmp = curl_version() ) ? $tmp['version'] : 'not available';
# Add to requirements
$requirements[] = array(
'name' => 'cURL version',
'value' => $curlVersion,
'ok' => $ok
);
# --------------------------------------
# Print page header
$output->bodyTitle = '欢迎使用您的控制面板';
#
# Glype news
#
echo <<<OUT
<p>该脚本提供了易于使用的界面来管理您的Glype。使用上面的导航开始。</p>
<h2>最新的Glype新闻...</h2>
<iframe scrolling="no" src="{$self}?fetch=news" style="width: 100%; height:150px; border: 1px solid #ccc;" onload="setTimeout('updateLatestVersion()',1000);"></iframe>
<br><br>
<h2>正在检查环境...</h2>
<ul class="green">
OUT;
# Print requirements
foreach ( $requirements as $li ) {
echo "<li>{$li['name']}: <span class=\"bold" . ( ! $li['ok'] ? ' error-color' : '' ) . "\">{$li['value']}</span></li>\r\n";
}
# End requirements
echo <<<OUT
</ul>
OUT;
# How are we doing - tell user if we're OK or not.
if ( $error->hasMsg() ) {
echo '<p><span class="bold error-color">Environment check failed</span>. You will not be able to run Glype until you fix the above issue(s).</p>';
} else {
echo '<p><span class="bold ok-color">环境还可以</span>. 您可以在此服务器上运行Glype。</p>';
}
#
# Script versions
#
$acpVersion = ADMIN_VERSION;
$proxyVersion = isset($CONFIG['version']) ? $CONFIG['version'] : 'unknown - pre 1.0';
# Create javascript to update the latest stable version
$javascript = <<<OUT
function updateLatestVersion(response) {
document.getElementById('current-version').innerHTML = '<img src="http://www.glype.com/feeds/proxy-version.php?cb={$cache_bust}" border="0" alt="version" />';
}
OUT;
$output->addJavascript($javascript);
# Print version summary
echo <<<OUT
<br>
<h2>正在检查脚本版本...</h2>
<ul class="green">
<li>控制面板版本: <b>{$acpVersion}</b></li>
<li>Glype 版本: <b>{$proxyVersion}</b></li>
<li>最新版本: <span class="bold" id="current-version">unknown</span></li>
</ul>
OUT;
# Is the settings file up to date?
function forCompare($val) { return str_replace(' ', '', $val); }
if ( $proxyVersion != 'unknown - pre 1.0' && version_compare(forCompare($acpVersion), forCompare($proxyVersion), '>') ) {
echo "<p><span class=\"bold error-color\">Note:</span> Your settings file needs updating. Use the <a href=\"{$self}?settings\">编辑设置</a> page and click Update.</p>";
}
# Add footer links
$output->addFooterLinks('Glype论坛:Proxy.org', 'http://proxy.org/forum/glype-proxy/');
break;
/*****************************************************************
* SETTINGS
******************************************************************/
case 'settings':
# Check the settings are writable
if ( ! is_writable(ADMIN_GLYPE_SETTINGS) ) {
$error->add('The settings file is not writable. You will not be able to save any changes. Please set permissions to allow PHP to write to <b>' . realpath(ADMIN_GLYPE_SETTINGS) . '</b>');
$tpl->disabled = ' disabled="disabled"';
}
# Load options into object
$options = simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?><options><section name="特殊选项" type="settings"><option key="license_key" type="string" input="text" styles="wide-input"><title>Glype许可证密钥</title><default>\'\'</default><desc>If you have purchased a license, please enter your license key here. Leave blank if you don\'t have a license.</desc></option><option key="enable_blockscript" type="bool" input="radio"><title>启用BlockScript</title><default>false</default><desc>BlockScript is security software which protects websites and empowers webmasters to stop unwanted traffic.</desc></option></section><section name="安装选项" type="settings"><option key="theme" type="string" input="select"><title>主题</title><default>\'default\'</default><desc>Theme/skin to use. This should be the name of the appropriate folder inside the /themes/ folder.</desc><generateOptions eval="true"><![CDATA[/* Check the dir exists */$themeDir = GLYPE_ROOT . \'/themes/\';if ( ! is_dir($themeDir) ) {return false;}/* Load folders from /themes/ */$dirs = scandir($themeDir);/* Loop through to create options string */$options = \'\';foreach ( $dirs as $dir ) {/* Ignore dotfiles */if ( $dir[0] == \'.\' ) {continue;}/* Add if this is valid theme */if ( file_exists($themeDir . $dir . \'/main.php\') ) {/* Make selected if this is our current theme */$selected = ( isset($currentValue) && $currentValue == $dir ) ? \' selected="selected"\' : \'\';/* Add option */$options .= "<option{$selected}>{$dir}</option>";}}return $options;]]></generateOptions></option><option key="plugins" type="string" input="text" styles="wide-input" readonly="readonly"><title>注册插件</title><default></default><desc>Run plugins on these websites</desc><toDisplay eval="true"><![CDATA[ if ($handle = opendir(GLYPE_ROOT."/plugins")) {while (($plugin=readdir($handle))!==false) {if (preg_match(\'#\.php$#\', $plugin)) {$plugin = preg_replace("#\.php$#", "", $plugin);$plugins[] = $plugin;}}closedir($handle);$plugin_list = implode(",", $plugins);} return $plugin_list; ]]></toDisplay><afterField>从插件目录自动生成。请勿编辑!</afterField></option><option key="tmp_dir" type="string" input="text" styles="wide-input"><title>临时目录</title><default>GLYPE_ROOT . \'/tmp/\'</default><desc>Temporary directory used by the script. Many features require write permission to the temporary directory. Ensure this directory exists and is writable for best performance.</desc><relative to="GLYPE_ROOT" desc="root proxy folder" /><isDir /></option><option key="gzip_return" type="bool" input="radio"><title>使用GZIP压缩</title><default>false</default><desc>Use GZIP compression when sending pages back to the user. This reduces bandwidth usage but at the cost of increased CPU load.</desc></option><option key="ssl_warning" type="bool" input="radio"><title>SSL 警告</title><default>true</default><desc>Warn users before browsing a secure site if on an insecure connection. This option has no effect if your proxy is on https.</desc></option><option key="override_javascript" type="bool" input="radio"><title>重写本机javascript</title><default>false</default><desc>The fastest and most reliable method of ensuring javascript is properly proxied is to override the native javascript functions with our own. However, this may interfere with any other javascript added to the page, such as ad codes.</desc></option><option key="load_limit" type="float" input="text" styles="small-input"><title>负载限制器</title><default>0</default><desc>This option fetches the server load and stops the script serving pages whenever the server load goes over the limit specified. Set to 0 to disable this feature.</desc><afterField eval="true"><![CDATA[/* Attempt to find the load */$load = ( ($uptime = @shell_exec(\'uptime\')) && preg_match(\'#load average: ([0-9.]+),#\', $uptime, $tmp) ) ? (float) $tmp[1] : false;if ( $load === false ) {return \'<span class="error-color">此功能不可用</span>. 找不到当前服务器负载.\';} else {return \'<span class="ok-color">Feature available here</span>. Current load: \' . $load;}]]></afterField></option><option key="footer_include" type="string" input="textarea" styles="wide-input"><title>页脚包括</title><default>\'\'</default><desc>Anything specified here will be added to the bottom of all proxied pages just before the <![CDATA[</body>]]> tag.</desc><toDisplay eval="true"><![CDATA[ return htmlentities($currentValue); ]]></toDisplay></option></section><section name="URL编码选项" type="settings"><option key="path_info_urls" type="bool" input="radio"><title>使用路径信息</title><default>false</default><desc>Formats URLs as browse.php/aHR0... instead of browse.php?u=aHR0... Path info may not be available on all servers.</desc></option></section><section name="直接链接" type="settings"><option key="stop_hotlinking" type="bool" input="radio"><title>防止热链接</title><default>true</default><desc>This option prevents users &quot;hotlinking&quot; directly to a proxied page and forces all users to first visit the index page. Note: hotlinking is also prevented when the &quot;Encrypt URL&quot; option is enabled.</desc></option><option key="hotlink_domains" type="array" input="textarea" styles="wide-input"><title>允许来自的热链接</title><default>array()</default><desc>If the above option is enabled, you can add individual referrers that are allowed to bypass the hotlinking protection. Note: hotlinking is also prevented when the &quot;Encrypt URL&quot; option is enabled.</desc><toDisplay eval="true"><![CDATA[ return implode("\r\n", $currentValue); ]]></toDisplay><toStore eval="true"><![CDATA[ $value = str_replace("\r", "\n", $value);$value=preg_replace("#\n+#", "\n", $value);return array_filter(explode("\n", $value));]]></toStore><afterField>Enter one domain per line</afterField></option></section><section name="登录中" type="settings"><comment><![CDATA[<p>您可能需要对来自代理IP地址的请求负责。如果通过代理进行非法活动,可以使用日志记录用户访问的页面的解密url.</p>]]></comment><option key="enable_logging" type="bool" input="radio"><title>启用日志记录</title><default>false</default><desc>Enable/disable the logging feature. If disabled, skip the rest of this section.</desc></option><option key="logging_destination" type="string" input="text" styles="wide-input"><title>日志文件夹路径</title><default>$CONFIG[\'tmp_dir\'] . \'logs/\'</default><desc>Enter a destination for log files. A new log file will be created each day in the directory specified. The directory must be writable. To protect against unauthorized access, place the log folder above your webroot.</desc><relative to="$CONFIG[\'tmp_dir\']" desc="temporary directory" /><isDir /></option><option key="log_all" type="bool" input="radio"><title>记录所有请求</title><default>false</default><desc>You can avoid huge log files by only logging requests for .html pages, as per the default setting. If you want to log all requests (images, etc.) as well, enable this.</desc></option></section><section name="网站访问控制" type="settings"><comment><![CDATA[<p>您可以使用白名单或黑名单限制通过代理访问网站:</p><ul class="black"><li>白名单:任何不在名单上的网站都将被阻止。.</li><li>黑名单:名单上的任何网站都将被屏蔽</li></ul>]]></comment><option key="whitelist" type="array" input="textarea" styles="wide-input"><title>白名单</title><default>array()</default><desc>Block everything except these websites</desc><toDisplay eval="true"><![CDATA[ return implode("\r\n", $currentValue); ]]></toDisplay><toStore eval="true"><![CDATA[ $value = str_replace("\r", "\n", $value);$value=preg_replace("#\n+#", "\n", $value);return array_filter(explode("\n", $value));]]></toStore><afterField>Enter one domain per line</afterField></option><option key="blacklist" type="array" input="textarea" styles="wide-input"><title>黑名单</title><default>array()</default><desc>Block these websites</desc><toDisplay eval="true"><![CDATA[ return implode("\r\n", $currentValue); ]]></toDisplay><toStore eval="true"><![CDATA[ $value = str_replace("\r", "\n", $value);$value=preg_replace("#\n+#", "\n", $value);return array_filter(explode("\n", $value));]]></toStore><afterField>Enter one domain per line</afterField></option></section><section name="用户访问控制" type="settings"><comment>您可以禁止用户通过IP地址访问您的代理。您可以用以下格式指定单个IP地址或IP地址范围<![CDATA[<p>:</p><ul class="black"><li>127.0.0.1</li><li>127.0.0.1-127.0.0.5</li><li>127.0.0.1/255.255.255.255</li><li>192.168.17.1/16</li><li>189.128/11</li></ul>]]></comment><option key="ip_bans" type="array" input="textarea" styles="wide-input"><title>禁止IP</title><default>array()</default><toDisplay eval="true"><![CDATA[ return implode("\r\n", $currentValue); ]]></toDisplay><toStore eval="true"><![CDATA[ $value = str_replace("\r", "\n", $value);$value=preg_replace("#\n+#", "\n", $value);return array_filter(explode("\n", $value));]]></toStore><afterField>Enter one IP address or IP address range per line</afterField></option></section><section name="转移选项" type="settings"><option key="connection_timeout" type="int" input="text" styles="small-input" unit="秒"><title>连接超时</title><default>5</default><desc>Time to wait for while establishing a connection to the target server. If the connection takes longer, the transfer will be aborted.</desc><afterField>使用0表示无限制</afterField></option><option key="transfer_timeout" type="int" input="text" styles="small-input" unit="秒"><title>传输超时</title><default>15</default><desc>Time to allow for the entire transfer. You will need a longer time limit to download larger files.</desc><afterField>使用0表示无限制</afterField></option><option key="max_filesize" type="int" input="text" styles="small-input" unit="MB"><title>文件大小限制</title><default>0</default><desc>Preserve bandwidth by limiting the size of files that can be downloaded through your proxy.</desc><toDisplay>return $currentValue ? round($currentValue/(1024*1024), 2) : 0;</toDisplay><toStore>return $value*1024*1024;</toStore><afterField>使用0表示无限制</afterField></option><option key="download_speed_limit" type="int" input="text" styles="small-input" unit="KB/s"><title>下载速度限制</title><default>0</default><desc>Preserve bandwidth by limiting the speed at which files are downloaded through your proxy. Note: if limiting download speed, you may need to increase the transfer timeout to compensate.</desc><toDisplay>return $currentValue ? round($currentValue/(1024), 2) : 0;</toDisplay><toStore>return $value*1024;</toStore><afterField>使用0表示无限制</afterField></option><option key="resume_transfers" type="bool" input="radio"><title>恢复传输</title><default>false</default><desc>This forwards any requested ranges from the client and this makes it possible to resume previous downloads. Depending on the &quot;Queue transfers&quot; option below, it may also allow users to download multiple segments of a file simultaneously.</desc></option><option key="queue_transfers" type="bool" input="radio"><title>队列传输</title><default>true</default><desc>You can limit use of your proxy to allow only one transfer at a time per user. Disable this for faster browsing.</desc></option></section><section name="Cookies" type="settings"><comment><![CDATA[<p>所有cookie必须发送到代理脚本。然后,脚本可以选择正确的cookie,以转发到目标服务器。但是,客户端的存储空间和服务器将接受的请求Cookie:标头的大小都有有限的限制。对于长时间浏览,您可能希望将Cookie存储在服务器端,以避免出现此问题。</p><br><p>这存在明显的隐私问题-如果使用此选项,请确保您的站点清楚说明其如何处理cookie并保护cookie数据免受未经授权的访问。</p>]]></comment><option key="cookies_on_server" type="bool" input="radio"><title>将Cookie存储在服务器上</title><default>false</default><desc>If enabled, cookies will be stored in the folder specified below.</desc></option><option key="cookies_folder" type="string" input="text" styles="wide-input"><title>Cookie文件夹的路径</title><default>$CONFIG[\'tmp_dir\'] . \'cookies/\'</default><desc>If storing cookies on the server, specify a folder to save the cookie data in. To protect against unauthorized access, place the cookie folder above your webroot.</desc><relative to="$CONFIG[\'tmp_dir\']" desc="temporary directory" /><isDir /></option><option key="encode_cookies" type="bool" input="radio"><title>编码cookie</title><default>false</default><desc>You can encode cookie names, domains and values with this option for optimum privacy but at the cost of increased server load and larger cookie sizes. This option has no effect if storing cookies on server.</desc></option></section><section name="保养" type="settings"><option key="tmp_cleanup_interval" type="float" input="text" styles="small-input" unit="小时"><title>清理间隔</title><default>48</default><desc>How often to clear the temporary files created by the script?</desc><afterField>使用0禁用</afterField></option><option key="tmp_cleanup_logs" type="float" input="text" styles="small-input" unit="天"><title>保留以下日志</title><default>30</default><desc>When should old log files be deleted? This option has no effect if the above option is disabled.</desc><afterField>使用0表示从不删除日志</afterField></option></section><section type="user" name="用户可配置选项"><option key="Encrypt URL" default="true" force="false">
<title>Encrypt URL</title><desc>Encrypts the URL of the page you are viewing for increased privacy. Note: this option is intended to obscure URLs and does not provide security. Use SSL for actual security.</desc></option><option key="encodePage" default="false" force="false"><title>加密页面</title><desc>通过在发送页面前对其进行加密,并在收到页面后使用javascript对其进行解密,有助于避免筛选。. 注意:此选项用于隐藏HTML源代码,不提供安全性。使用SSL实现实际的安全性.</desc></option><option key="showForm" default="true" force="true"><title>Show Form</title><desc>This provides a mini-form at the top of each page that allows you to quickly jump to another site without returning to our homepage.</desc></option><option key="allowCookies" default="true" force="false"><title>Allow Cookies</title><desc>Cookies may be required on interactive websites (especially where you need to log in) but advertisers also use cookies to track your browsing habits.</desc></option><option key="tempCookies" default="true" force="true"><title>Force Temporary Cookies</title><desc>This option overrides the expiry date for all cookies and sets it to at the end of the session only - all cookies will be deleted when you shut your browser. (Recommended)</desc></option><option key="stripTitle" default="false" force="true"><title>Remove Page Titles</title><desc>Removes titles from proxied pages.</desc></option><option key="stripJS" default="true" force="false"><title>Remove Scripts</title><desc>Remove scripts to protect your anonymity and speed up page loads. However, not all sites will provide an HTML-only alternative. (Recommended)</desc></option><option key="stripObjects" default="false" force="false"><title>Remove Objects</title><desc>You can increase page load times by removing unnecessary Flash, Java and other objects. If not removed, these may also compromise your anonymity.</desc></option></section><section type="forced" hidden="true" name="Do not edit this section manually!"><option key="version" type="string"><default>\''.ADMIN_VERSION.'\'</default><desc>Settings file version for determining compatibility with admin tool.</desc></option></section></options>');
#
# SAVE CHANGES
#
if ( $input->pSubmit && ! $error->hasMsg() ) {
# Filter inputs to create valid PHP code
function filter($value, $type) {
switch ( $type ) {
# Quote strings
case 'string':
default:
return quote($value);
# Clean integers
case 'int':
return intval($value);
# Float
case 'float':
if ( is_numeric($value) ) {
return $value;
}
return quote($value);
# Create arrays - make empty array if no value, not an array with a single empty value
case 'array':
$args = $value ? implode(', ', array_map('quote', (array) $value)) : '';
return 'array(' . $args . ')';
# Bool - check we have a real bool and resort to default if not
case 'bool':
if ( bool($value) === NULL ) {
global $option;
$value = $option->default;
}
return $value;
}
}
# Create a comment line
function comment($text, $multi=false) {
# Comment marker
$char = $multi ? '*' : '#';
# Split and make newlines with the comment char
$text = wordwrap($text, 65, "\r\n$char ");
# Return a large comment
if ( $multi ) {
return '/*****************************************************************
* ' . $text . '
******************************************************************/';
}
# Return a small comment
return "# $text";
}
# Prepare the file header
$toWrite = '<?php
/*******************************************************************
* Glype is copyright and trademark 2007-2015 UpsideOut, Inc. d/b/a Glype
* and/or its licensors, successors and assigners. All rights reserved.
*
* Use of Glype is subject to the terms of the Software License Agreement.
* http://www.glype.com/license.php
*******************************************************************
* Our settings file. Self-explanatory - stores the config values.
*******************************************************************
* This file has been automatically generated by the glype admin tool.
* For a more complete and thorough explanation of options, consult
* the original settings.php file from the glype package.
******************************************************************/
';
# Loop through all the sections
foreach ( $options->section as $section ) {
# Add section header to the file
$toWrite .= NL . NL . comment($section['name'], true) . NL;
# Now go through this section's options
foreach ( $section->option as $option ) {
$key = (string) $option['key'];
# Grab the posted value
$value = $input->{'p' . $key};
# The user-configurable options need special treatment
if ( $section['type'] == 'user' ) {
# We need to save 4 values - title, desc, default and force
$title = filter( ( isset($value['title']) ? $value['title'] : $option->title ), 'string');
$desc = filter( ( isset($value['desc']) ? $value['desc'] : $option->desc ), 'string');
$default = filter( ( isset($value['default']) ? $value['default'] : $option['default']), 'bool');
$force = isset($value['force']) ? 'true' : 'false';
# Write them
$toWrite .=
"\r\n\$CONFIG['options'][" . quote($key) . "] = array(
'title' => $title,
'desc' => $desc,
'default' => $default,
'force' => $force
);\r\n";
# Finished saving, move to next
continue;
}
# Do we have a posted value or is it forced?
if ( $value === NULL || $section['forced'] ) {
# Resort to default (which comes ready quoted)
$value = $option->default;
} else {
# Yes, apply quotes and any pre-storage logic
if ( $option->toStore && ($tmp = @eval($option->toStore)) ) {
$value = $tmp;
}
# Normalize directory paths
if ( $option->isDir ) {
# Use forward slash only
$value = str_replace('\\', '/', $value);
# Add trailing slash
if ( substr($value, -1) && substr($value, -1) != '/' ) {
$value .= '/';
}
}
# Filter it according to desired var type
$value = filter($value, $option['type']);
# Add any relativeness
if ( $option->relative && $input->{'pRelative_' . $key} ) {
$value = $option->relative['to'] . ' . ' . $value;
}
}
# Add to file (commented description and $CONFIG value)
$toWrite .= NL . comment($option->desc) . NL;
if ($key=='enable_blockscript' && $value=='true') {
$value='false';
if (function_exists('ioncube_loader_version')&&file_exists($_SERVER['DOCUMENT_ROOT'].'/blockscript/detector.php')) {$value='true';}
}
$toWrite .= '$CONFIG[' . quote($key) . '] = ' . $value . ';' . NL;
}
}
# Extract any preserved details
$file = file_get_contents(ADMIN_GLYPE_SETTINGS);
# And add to file
if ( $tmp = strpos($file, '//---PRESERVE ME---') ) {
$toWrite .= NL . substr($file, $tmp);
}
# Finished, save to file
if ( file_put_contents(ADMIN_GLYPE_SETTINGS, $toWrite) ) {
$confirm->add('设置文件已更新。');
} else {
$error->add('The settings file failed to write. The file was detected as writable but file_put_contents() returned false.');
}
# And redirect to reload the new settings
$location->redirect('settings');
}
#
# SHOW FORM
#
# Set up page variables
$output->title = '编辑设置';
$output->bodyTitle = 'edit settings';
# Print form
echo <<<OUT
<p>该页面允许您编辑配置以自定义和调整代理。如果不清楚选项,请将鼠标悬停在选项名称上以获取更详细的描述. <a href="#notes">更多</a></p>
<form action="{$self}?settings" method="post">
OUT;
# Add an "Update" button. Functionally identical to "Save".
function forCompare($val) { return str_replace(' ', '', $val); }
if ( empty($CONFIG['version']) || version_compare(forCompare(ADMIN_VERSION), forCompare($CONFIG['version']), '>') ) {
echo '<p class="error-color">Your settings file needs updating. <input class="button" type="submit" name="submit" value="Update &raquo;"></p>';
}
# Add the javascript for this page
$javascript = <<<OUT
// Create ajax "loading" image
window.loadingImage = '<img src="{$self}?image=loading.gif" width="16" height="16" alt="loading...">';
// Toggle "relative from root" option
function toggleRelative(checkbox, textId) {
var textField = document.getElementById(textId);
var relative = checkbox.value;
// Are we adding or taking away?
if ( ! checkbox.checked ) {
// Does the field already contain the relative path?
if ( textField.value.indexOf(relative) != 0 ) {
textField.value = relative += textField.value;
}
} else {
textField.value = textField.value.replace(relative, '');
}
}
// Check if a given directory exists / is_writable
var testDir = function(fieldName) {
// Save vars in object
this.input = document.getElementById(fieldName);
this.result = document.getElementById('dircheck_' + fieldName);
this.relative = document.getElementById('relative_' + fieldName);
this.isTmp = fieldName == 'tmp_dir';
// Update status
this.updateDirStatus = function(response) {
this.result.innerHTML = response;
}
// Run when value is changed
this.changed = function() {
this.isRelative = this.relative ? this.relative.checked : false;
// Attempt to get path from the value
var dirPath = this.input.value;
// Is it relative?
if ( this.isRelative ) {
dirPath = this.relative.value + dirPath;
}
// Update with the loading .gif
this.result.innerHTML = loadingImage;
// Make the request
runAjax('$self?fetch=test-dir&dir=' + encodeURIComponent(dirPath) + '&tmp=' + this.isTmp, null, this.updateDirStatus, this);
}
}
OUT;
$output->addJavascript($javascript);
# Go through all options and print the form
foreach ( $options->section as $section ) {
# Print title if we're displaying this
if ( $section['hidden'] === NULL ) {
echo '
<br>
<div class="hr"></div>
<h2>' . $section['name'] . '</h2>';
}
# What type of section is this?
switch ( $section['type'] ) {
# Standard option/value pairs
case 'settings':
# Comment
if ( $section->comment ) {
echo '<div class="comment">',$section->comment,'</div>';
}
# Print table header
echo <<<OUT
<table class="form_table" border="0" cellpadding="0" cellspacing="0">
OUT;
# Loop through the child options
foreach ( $section->option as $option ) {
# Reset variables
$field = '';
# Convert to string so we can use it as an array index
$key = (string) $option['key'];
# Find current value (if we have one)
$currentValue = isset($CONFIG[$key]) ? $CONFIG[$key] : @eval('return ' . $option->default . ';');
# If the option can be relative, find out what we're relative from
if ( $option->relative ) {
# Run code from options XML to get value
$relativeTo = @eval('return ' . $option->relative['to'] . ';');
# Remove that from the current value
$currentValue = str_replace($relativeTo, '', $currentValue, $relativeChecked);
}
# If the option has any "toDisplay" filtering, apply it
if ( $option->toDisplay && ( $newValue = @eval($option->toDisplay) ) !== false ) {
$currentValue = $newValue;
}
# Create attributes (these are fairly consistent in multiple option types)
$attr = <<<OUT
type="{$option['input']}" name="{$option['key']}" id="{$option['key']}" value="{$currentValue}" class="inputgri {$option['styles']}"
OUT;
# Prepare the input
switch ( $option['input'] ) {
# TEXT FIELD
case 'text':
# Add onchange to test dirs
if ( $option->isDir ) {
$attr .= " onchange=\"test{$option['key']}.changed()\"";
}
$field = '<input' . $attr . '>';
# Can we be relative to another variable?
if ( $option->relative ) {
# Is the box already checked?
$checked = empty($relativeChecked) ? '' : ' checked="checked"';
# Escape backslashes so we can use it in javascript
$relativeToEscaped = str_replace('\\', '\\\\', $relativeTo);
# Add to existing field
$field .= <<<OUT
<input type="checkbox" onclick="toggleRelative(this,'{$option['key']}')" value="{$relativeTo}" name="relative_{$option['key']}" id="relative_{$option['key']}"{$checked}>
<label class="tooltip" for="relative_{$option['key']}" onmouseover="tooltip('You can specify the value as relative to the {$option->relative['desc']}:<br><b>{$relativeToEscaped}</b>')" onmouseout="exit();">Relative to {$option->relative['desc']}</label>
OUT;
}
break;
# SELECT FIELD
case 'select':
$field = '<select' . $attr . '>' . @eval($option->generateOptions). '</select>';
break;
# RADIO
case 'radio':
$onChecked = $currentValue ? ' checked="checked"' : '';
$offChecked = ! $currentValue ? ' checked="checked"' : '';
$field = <<<OUT
<input type="radio" name="{$option['key']}" id="{$option['key']}_on" value="true" class="inputgri {$option['styles']}"{$onChecked}>
<label for="{$option['key']}_on">是</label>
&nbsp; / &nbsp;
<input type="radio" name="{$option['key']}" id="{$option['key']}_off" value="false" class="inputgri {$option['styles']}"{$offChecked}>
<label for="{$option['key']}_off">不</label>
OUT;
break;
# TEXTAREA
case 'textarea':
$field = '<textarea ' . $attr . '>' . $currentValue . '</textarea><br>';
break;
}
# Is there a description to use as tooltip?
$tooltip = $option->desc ? 'class="tooltip" onmouseover="tooltip(\'' . htmlentities(addslashes($option->desc), ENT_QUOTES) . '\')" onmouseout="exit()"' : '';
# Add units
if ( $option['unit'] ) {
$field .= ' ' . $option['unit'];
}
# Any after field text to add?
if ( $option->afterField ) {
# Code to eval or string?
$add = $option->afterField['eval'] ? @eval($option->afterField) : $option->afterField;
# Add to field
if ( $add ) {
$field .= ' (<span class="little">' . $add . '</span>)';
}
}
echo <<<OUT
<tr>
<td width="160" align="right">
<label for="{$option['key']}" {$tooltip}>{$option->title}:</label>
</td>
<td>{$field}</td>
</tr>
OUT;
# Is this a directory path we're expecting?
if ( $option->isDir ) {
# Write with javascript to hide from non-js browsers
$write = jsWrite('(<a style="cursor:pointer;" onclick="test' . $option['key'] . '.changed()">再试一次</a>)');
echo <<<OUT
<tr>
<td>&nbsp;</td>
<td>
&nbsp;&nbsp;
<span id="dircheck_{$option['key']}"></span>
$write
</td>
</tr>
OUT;
$output->addDomReady("window.test{$option['key']} = new testDir('{$option['key']}');test{$option['key']}.changed();");
}
}
echo '</table>';
break;
# User configurable options
case 'user':
# Print table header
echo <<<OUT
<table class="table" cellpadding="0" cellspacing="0">
<tr class="table_header">
<td width="200">标题</td>
<td width="50">默认</td>
<td>描述</td>
<td width="50">强制 <span class="tooltip" onmouseover="tooltip('Forced options do not appear on the proxy form and will always use the default value')" onmouseout="exit()">?</span></td>
</tr>
OUT;
# Find the current options
$currentOptions = isset($CONFIG['options']) ? $CONFIG['options'] : array();
# Print options
foreach ( $section->option as $option ) {
# Get values from XML
$key = (string) $option['key'];
# Get values from current settings, resorted to XML if not available
$title = isset($currentOptions[$key]['title']) ? $currentOptions[$key]['title'] : $option->title;
$default = isset($currentOptions[$key]['default']) ? $currentOptions[$key]['default'] : bool($option['default']);
$desc = isset($currentOptions[$key]['desc']) ? $currentOptions[$key]['desc'] : $option->desc;
$force = isset($currentOptions[$key]['force']) ? $currentOptions[$key]['force'] : bool($option['force']);
# Determine checkboxes
$on = $default == true ? ' checked="checked"' : '';
$off = $default == false ? ' checked="checked"' : '';
$force = $force ? ' checked="checked"' : '';
# Row color
$row = isset($row) && $row == 'row1' ? 'row2' : 'row1';
echo <<<OUT
<tr class="{$row}">
<td><input type="text" class="inputgri" style="width:95%;" name="{$key}[title]" value="{$title}"></td>
<td>
<input type="radio" name="{$key}[default]" value="true" id="options_{$key}_on"{$on}> <label for="options_{$key}_on">On</label>
<br>
<input type="radio" name="{$key}[default]" value="false" id="options_{$key}_off"{$off}> <label for="options_{$key}_off">Off</label>
</td>
<td><textarea class="inputgri wide-input" name="{$key}[desc]">{$desc}</textarea></td>
<td><input type="checkbox" name="{$key}[force]"{$force} value="true"></td>
</tr>
OUT;
}
# Print table footer
echo '</table>';
break;
}
}
# Page footer
echo <<<OUT
<div class="hr"></div>
<p class="center"><input class="button" type="submit" name="submit" value="保存更改"{$tpl->disabled}></p>
</form>
<div class="hr"></div>
<h2><a name="notes"></a>笔记:</h2>
<ul class="black">
<li>临时目录:许多功能要求对临时目录具有写访问权限。如果使用以下任何功能,请确保相应地设置了权限:日志记录,服务器端cookie,维护/清理和服务器负载限制器。</li>
<li>敏感数据:某些临时文件可能包含应保密的个人数据,即日志文件和服务器端cookie。如果使用这些功能,请通过选择Webroot上方的合适位置或使用.htaccess文件拒绝访问来防止未经授权的访问。</li>
<li>相对路径:您可以指定一些相对于其他路径的路径。例如,如果在/ [tmp_dir] / logs /中创建日志(按照默认设置),则可以编辑tmp_dir的值,日志路径将自动更新。</li>
<li>快速入门:默认情况下,所有临时文件都在/ tmp /目录中创建。根据需要创建功能的子文件夹。私有文件受.htaccess文件保护。如果运行的是Apache,则只需在/ tmp /目录(0755或0777)上设置可写权限,并且所有功能都可以使用,而无需进一步更改文件系统或权限。</li>
</ul>
<p class="right"><a href="#">^ 顶部</a></p>
OUT;
break;
/*****************************************************************
* BlockScript
******************************************************************/
case 'blockscript':
if (file_exists($bsc=$_SERVER['DOCUMENT_ROOT'].'/blockscript/tmp/config.php')) {
include($bsc);
# header('Location: /blockscript/detector.php?blockscript=setup&bsap='.$BS_VAL['admin_password']); exit;
}
$installed = isset($BS_VAL['license_agreement_accepted']) ? '<span class="ok-color">installed</span>' : '<span class="error-color">not installed</span>';
$enabled = (isset($BS_VAL['license_agreement_accepted']) && !empty($CONFIG['enable_blockscript'])) ? '<span class="ok-color">enabled</span>' : '<span class="error-color">disabled</span>';
if (!($ok=function_exists('ioncube_loader_version'))) {$error->add('BlockScript requires IonCube.');}
$IonCubeVersion = $ok && ( $tmp = ioncube_loader_version() ) ? $tmp : 'not available';
if ($ok && $tmp!='not available') {
}
# Print header
$output->title = 'BlockScript&reg;';
$output->bodyTitle = 'BlockScript&reg; Integration';
echo <<<OUT
<form action="{$self}?blockscript" method="post">
<table class="form_table" border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="right">BlockScript status:</td>
<td><b>{$installed} and {$enabled}</b></td>
</tr>
</table>
</form>
<div class="hr"></div>
<h2>About</h2>
<p><a href="https://www.blockscript.com/" target="_blank">BlockScript</a> is security software which protects websites and empowers webmasters to stop unwanted traffic. BlockScript detects and blocks requests from all types of proxy servers and anonymity networks, hosting networks, undesirable robots and spiders, and even entire countries.</p>
<p>BlockScript can help proxy websites by blocking filtering company spiders and other bots. BlockScript detects and blocks: barracudanetworks.com, bluecoat.com, covenanteyes.com, emeraldshield.com, ironport.com, lightspeedsystems.com, mxlogic.com, n2h2.com, netsweeper.com, securecomputing.com, mcafee.com, sonicwall.com, stbernard.com, surfcontrol.com, symantec.com, thebarriergroup.com, websense.com, and much more.</p>
<p>BlockScript provides free access to core features and <a href="https://www.blockscript.com/pricing.php" target="_blank">purchasing a license key</a> unlocks all features. A one week free trial is provided so that you can fully evaluate all features of the software.</p>
<div class="hr"></div>
<h2>Installation Instructions</h2>
<ol>
<li><a href="https://www.blockscript.com/download.php" target="_blank">Download BlockScript</a> and extract the contents of the .zip file.</li>
<li>Upload the &quot;blockscript&quot; directory and its contents.</li>
<li>CHMOD 0777 (or 0755 if running under suPHP) the &quot;detector.php&quot; file and the &quot;/blockscript/tmp/&quot; directory.</li>
<li>Visit <a href="http://{$_SERVER['HTTP_HOST']}/blockscript/detector.php" target="_blank">http://{$_SERVER['HTTP_HOST']}/blockscript/detector.php</a> in your browser.</li>
<li>Follow the on-screen prompts in your BlockScript control panel.</li>
</ol>
<br>
OUT;
if ($bsc) {
$admin_password = isset($BS_VAL['admin_password']) ? $BS_VAL['admin_password'] : '';
echo '<div class="hr"></div><h2>Your BlockScript Installation</h2><p><a href="/blockscript/detector.php?blockscript=setup&bsap='.$admin_password.'" target="_blank">Login To Your BlockScript Control Panel</a></p>';
}
break;
/*****************************************************************
* LOG INDEX
******************************************************************/
case 'logs':
# Are we updating the log destination?
if ( $input->pDestination !== NULL ) {
# Attempt to validate path
$path = realpath($input->pDestination);
# Is the path OK?
if ( $path ) {
$confirm->add('Log folder updated.');
} else {
$error->add('Log folder not updated. <b>' . $input->pDestination . '</b> does not exist.');
}
# Normalize
$path = str_replace('\\', '/', $path);
# Add trailing slash
if ( isset($path[strlen($path)-1]) && $path[strlen($path)-1] != '/' ) {
$path .= '/';
}
# Save in session
$_SESSION['logging_destination'] = $path;
# Redirect to avoid "Resend Post?" on refresh
$location->redirect('logs');
}
# Find status
$enabled = empty($CONFIG['enable_logging']) == false;
$status = $enabled ? '<span class="ok-color">enabled</span>' : '<span class="error-color">disabled</span>';
$destination = isset($CONFIG['logging_destination']) ? $CONFIG['logging_destination'] : '';
# Are we overriding the real destination with some other value?
if ( ! empty($_SESSION['logging_destination']) ) {
$destination = $_SESSION['logging_destination'];
}
# Print header
$output->title = 'log viewer';
$output->bodyTitle = '记录中';
echo <<<OUT
<form action="{$self}?logs" method="post">
<table class="form_table" border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="right">记录功能:</td>
<td><b>{$status}</b></td>
</tr>
<tr>
<td align="right"><span class="tooltip" onmouseover="tooltip('The value here is for viewing and analysing logs only - changing this has no effect on the proxy logging feature itself and will not change the folder in which new log files are created.')" onmouseout="exit()">日志文件夹</span>:</td>
<td><input type="text" name="destination" class="inputgri wide-input" value="{$destination}"> <input type="submit" class="button" value="Update &raquo;"></td>
</tr>
</table>
</form>
<div class="hr"></div>
<h2>日志文件</h2>
OUT;
# Do we have any log files to analyze?
if ( ! ( file_exists($destination) && is_dir($destination) && ($logFiles = scandir($destination, 1)) ) ) {
# Print none and exit
echo '<p>没有要分析的日志文件.</p>';
break;
}
# Print starting table
echo <<<OUT
<table class="table" cellpadding="0" cellspacing="0">
OUT;
# Set up starting vars
$currentYearMonth = false;
$first = true;
$totalSize = 0;
# Go through all files
foreach ( $logFiles as $file ) {
# Verify files is a glype log. Log files formatted as YYYY-MM-DD.log
if ( ! ( strlen($file) == 14 && preg_match('#^([0-9]{4})-([0-9]{2})-([0-9]{2})\.log$#', $file, $matches) ) ) {
continue;
}
# Extract matches
list(, $yearNumeric, $monthNumeric, $dayNumeric) = $matches;
# Convert filename to timestamp
$timestamp = strtotime(str_replace('.log', ' 12:00 PM', $file));
# Extract time parts
$month = date('F', $timestamp);
$day = date('l', $timestamp);
$display = date('jS', $timestamp) . ' (' . $day . ')';
$yearMonth = $yearNumeric . '-' . $monthNumeric;
# Display in bold if today
if ( $display == date('jS (l)') ) {
$display = '<b>' . $display . '</b>';
}
# Is this a new month?
if ( $yearMonth != $currentYearMonth ) {
# Print in a separate table (unless first)
if ( $first == false ) {
echo <<<OUT
</table>
<br>
<table class="table" cellpadding="0" cellspacing="0">
OUT;
}
# Print table header
echo <<<OUT
<tr class="table_header">
<td colspan="2">{$month} {$yearNumeric}</td>
<td>[<a href="{$self}?logs-view&month={$yearMonth}&show=popular-sites">popular sites</a>]</td>
</tr>
OUT;
# Update vars so we don't do this again until we want to
$currentYearMonth = $yearMonth;
$first = false;
}
# Format size
$filesize = filesize($destination . $file);
$totalSize += $filesize;
$size = formatSize($filesize);
# Row color is grey if weekend
$row = ( $day == 'Saturday' || $day == 'Sunday' ) ? '3' : '1';
# Print log file row
echo <<<OUT
<tr class="row{$row}">
<td width="150">{$display}</td>
<td width="100">{$size}</td>
<td>
[<a href="{$self}?logs-view&file={$file}&show=raw" target="_blank" title="Opens in a new window">raw log</a>]
&nbsp;
[<a href="{$self}?logs-view&file={$file}&show=popular-sites">popular sites</a>]
</td>
</tr>
OUT;
}
# End table
$total = formatSize($totalSize);
echo <<<OUT
</table>
<p>Total space used by logs: <b>{$total}</b></p>
<p class="little">Note: Raw logs open in a new window.</p>
<p class="little">Note: You can set up your proxy to automatically delete old logs with the maintenance feature.</p>
OUT;
break;
/*****************************************************************
* LOG VIEWER
******************************************************************/
case 'logs-view':
$output->title = 'view log';
$output->bodyTitle = 'View log file';
# Find log folder
$logFolder = isset($_SESSION['logging_destination']) ? $_SESSION['logging_destination'] : $CONFIG['logging_destination'];
# Verify folder is valid
if ( ! file_exists($logFolder) || ! is_dir($logFolder) ) {
$error->add('The log folder specified does not exist.');
break;
}
# Find file
$file = $input->gFile ? realpath($logFolder . '/' . str_replace('..', '', $input->gFile)) : false;
# What type of viewing do we want?
switch ( $input->gShow ) {
# Raw log file
case 'raw':
# Find file
if ( $file == false || file_exists($file) == false ) {
$error->add('The file specified does not exist.');
break;
}
# Use raw wrapper
$output = new RawOutput;
# And load file
readfile($file);
break;
# Stats - most visited site
case 'popular-sites':
# Scan files to find most popular sites
$scan = array();
# Find files to scan
if ( $file ) {
# Single file mode
$scan[] = $file;
# Date of log file
$date = ( $fileTime = strtotime(basename($input->gFile, '.log')) ) ? date('l jS F, Y', $fileTime) : '[unknown]';
} else if ( $input->gMonth && strlen($input->gMonth) > 5 && ( $logFiles = scandir($logFolder) ) ) {
# Month mode - use all files in given month
foreach ( $logFiles as $file ) {
# Match name
if ( strpos($file, $input->gMonth) === 0 ) {
$scan[] = realpath($logFolder . '/' . $file);
}
}
# Date of log files
$date = date('F Y', strtotime($input->gMonth . '-01'));
}
# Check we have some files to scan
if ( empty($scan) ) {
$error->add('No files to analyze.');
break;
}
# Data array
$visited = array();
# Read through files
foreach ( $scan as $file ) {
# Allow extra time
@set_time_limit(30);
# Open handle to file
if ( ( $handle = fopen($file, 'rb') ) === false ) {
continue;
}
# Scan for URLs
while ( ( $data = fgetcsv($handle, 2000) ) !== false ) {
# Extract URLs
if ( isset($data[2]) && preg_match('#(?:^|\.)([a-z0-9-]+\.(?:[a-z]{2,}|[a-z.]{5,6}))$#i', strtolower(parse_url(trim($data[2]), PHP_URL_HOST)), $tmp) ) {
# Add to tally
if ( isset($visited[$tmp[1]]) ) {
# Increment an existing count
++$visited[$tmp[1]];
} else {
# Create a new item
$visited[$tmp[1]] = 1;
}
}
}
# Close handle to free resources
fclose($handle);
}
# Sort
arsort($visited);
# Truncate to first X results
$others = array_splice($visited, ADMIN_STATS_LIMIT);
# Sum up the "others" group
$others = array_sum($others);
# Print header
echo <<<OUT
<h2>Most visited sites for {$date}</h2>
<table class="form_table" cellpadding="0" cellspacing="0" width="100%">
OUT;
# Find largest value
$max = max($visited);
# Create horizontal bar chart type thing
foreach ( $visited as $site => $count ) {
$rowWidth = round(($count/$max)*100);
# Print it
echo <<<OUT
<tr>
<td width="200" align="right">{$site}</td>
<td><div class="bar" style="width: {$rowWidth}%;">{$count}</div></td>
</tr>
OUT;
}
# Table footer
echo <<<OUT
<tr>
<td align="right"><i>Others</i></td>
<td>{$others}</td>
</tr>
</table>
<p class="align-center">&laquo; <a href="{$self}?logs">Back</a></p>
OUT;
break;
# Anything else - ignore
default:
$error->add('Missing input. No log view specified.');
}
break;
/*****************************************************************
* Everything else - 404
******************************************************************/
default:
# Send 404 status
$output->sendStatus(404);
# And print the error page
$output->title = 'page not found';
$output->bodyTitle = 'Page Not Found (404)';
echo <<<OUT
<p>The requested page <b>{$_SERVER['REQUEST_URI']}</b> was not found.</p>
OUT;
}
/*****************************************************************
* Send content wrapped in our theme
******************************************************************/
# Get buffer
$content = ob_get_contents();
# Clear buffer
ob_end_clean();
# Add content
$output->addContent($content);
# And print
$output->out();
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化