mirror of https://github.com/BOINC/boinc.git
parent
47f44b9d8c
commit
04a155ec46
|
@ -147,8 +147,10 @@ int boinc_init() {
|
|||
strcpy(aid.user_name, "John Smith");
|
||||
strcpy(aid.team_name, "The A-Team");
|
||||
aid.wu_cpu_time = 1000;
|
||||
aid.total_cobblestones = 1000;
|
||||
aid.recent_avg_cobblestones = 500;
|
||||
aid.user_total_credit = 1000;
|
||||
aid.user_expavg_credit = 500;
|
||||
aid.host_total_credit = 1000;
|
||||
aid.host_expavg_credit = 500;
|
||||
aid.checkpoint_period = DEFAULT_CHECKPOINT_PERIOD;
|
||||
aid.fraction_done_update_period = DEFAULT_FRACTION_DONE_UPDATE_PERIOD;
|
||||
|
||||
|
@ -527,13 +529,17 @@ int write_init_data_file(FILE* f, APP_INIT_DATA& ai) {
|
|||
}
|
||||
fprintf(f,
|
||||
"<wu_cpu_time>%f</wu_cpu_time>\n"
|
||||
"<total_cobblestones>%f</total_cobblestones>\n"
|
||||
"<recent_avg_cobblestones>%f</recent_avg_cobblestones>\n"
|
||||
"<user_total_credit>%f</user_total_credit>\n"
|
||||
"<user_expavg_credit>%f</user_expavg_credit>\n"
|
||||
"<host_total_credit>%f</host_total_credit>\n"
|
||||
"<host_expavg_credit>%f</host_expavg_credit>\n"
|
||||
"<checkpoint_period>%f</checkpoint_period>\n"
|
||||
"<fraction_done_update_period>%f</fraction_done_update_period>\n",
|
||||
ai.wu_cpu_time,
|
||||
ai.total_cobblestones,
|
||||
ai.recent_avg_cobblestones,
|
||||
ai.user_total_credit,
|
||||
ai.user_expavg_credit,
|
||||
ai.host_total_credit,
|
||||
ai.host_expavg_credit,
|
||||
ai.checkpoint_period,
|
||||
ai.fraction_done_update_period
|
||||
);
|
||||
|
@ -554,8 +560,10 @@ int parse_init_data_file(FILE* f, APP_INIT_DATA& ai) {
|
|||
}
|
||||
else if (parse_str(buf, "<user_name>", ai.user_name, sizeof(ai.user_name))) continue;
|
||||
else if (parse_str(buf, "<team_name>", ai.team_name, sizeof(ai.team_name))) continue;
|
||||
else if (parse_double(buf, "<total_cobblestones>", ai.total_cobblestones)) continue;
|
||||
else if (parse_double(buf, "<recent_avg_cobblestones>", ai.recent_avg_cobblestones)) continue;
|
||||
else if (parse_double(buf, "<user_total_credit>", ai.user_total_credit)) continue;
|
||||
else if (parse_double(buf, "<user_expavg_credit>", ai.user_expavg_credit)) continue;
|
||||
else if (parse_double(buf, "<host_total_credit>", ai.host_total_credit)) continue;
|
||||
else if (parse_double(buf, "<host_expavg_credit>", ai.host_expavg_credit)) continue;
|
||||
else if (parse_double(buf, "<wu_cpu_time>", ai.wu_cpu_time)) continue;
|
||||
else if (parse_double(buf, "<checkpoint_period>", ai.checkpoint_period)) continue;
|
||||
else if (parse_double(buf, "<fraction_done_update_period>", ai.fraction_done_update_period)) continue;
|
||||
|
|
|
@ -56,8 +56,10 @@ struct APP_INIT_DATA {
|
|||
char user_name[256];
|
||||
char team_name[256];
|
||||
double wu_cpu_time; // cpu time from previous sessions
|
||||
double total_cobblestones;
|
||||
double recent_avg_cobblestones;
|
||||
double user_total_credit;
|
||||
double user_expavg_credit;
|
||||
double host_total_credit;
|
||||
double host_expavg_credit;
|
||||
double checkpoint_period; // recommended checkpoint period
|
||||
double fraction_done_update_period;
|
||||
};
|
||||
|
|
47
client/app.C
47
client/app.C
|
@ -134,12 +134,19 @@ int ACTIVE_TASK::start(bool first_time) {
|
|||
|
||||
memset(&aid, 0, sizeof(aid));
|
||||
|
||||
// TODO: fill in the app prefs, team name, etc.
|
||||
strncpy( aid.user_name, wup->project->user_name, 256 );
|
||||
if (wup->project->project_specific_prefs)
|
||||
strncpy( aid.app_preferences, wup->project->project_specific_prefs, 4096 );
|
||||
aid.total_cobblestones = wup->project->user_total_credit;
|
||||
aid.recent_avg_cobblestones = wup->project->user_expavg_credit;
|
||||
strncpy(aid.user_name, wup->project->user_name, sizeof(aid.user_name));
|
||||
strncpy(aid.team_name, wup->project->team_name, sizeof(aid.team_name));
|
||||
if (wup->project->project_specific_prefs) {
|
||||
strncpy(
|
||||
aid.app_preferences,
|
||||
wup->project->project_specific_prefs,
|
||||
sizeof(aid.app_preferences)
|
||||
);
|
||||
}
|
||||
aid.user_total_credit = wup->project->user_total_credit;
|
||||
aid.user_expavg_credit = wup->project->user_expavg_credit;
|
||||
aid.host_total_credit = wup->project->host_total_credit;
|
||||
aid.host_expavg_credit = wup->project->host_expavg_credit;
|
||||
aid.checkpoint_period = DEFAULT_CHECKPOINT_PERIOD;
|
||||
aid.fraction_done_update_period = DEFAULT_FRACTION_DONE_UPDATE_PERIOD;
|
||||
aid.wu_cpu_time = checkpoint_cpu_time;
|
||||
|
@ -728,34 +735,28 @@ bool ACTIVE_TASK_SET::poll_time() {
|
|||
return updated;
|
||||
}
|
||||
|
||||
// Gets the next available free slot, or returns -1 if all slots are full
|
||||
// TODO: don't use malloc here
|
||||
// Get the next available free slot, or returns -1 if all slots are full
|
||||
//
|
||||
int ACTIVE_TASK_SET::get_free_slot(int total_slots) {
|
||||
unsigned int i;
|
||||
char *slot_status;
|
||||
int j;
|
||||
bool found;
|
||||
|
||||
if (active_tasks.size() >= (unsigned int)total_slots) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
slot_status = (char *)calloc( sizeof(char), total_slots );
|
||||
if (!slot_status) return -1;
|
||||
|
||||
for (i=0; i<active_tasks.size(); i++) {
|
||||
if (active_tasks[i]->slot >= 0 && active_tasks[i]->slot < total_slots) {
|
||||
slot_status[active_tasks[i]->slot] = 1;
|
||||
for (j=0; j<total_slots; j++) {
|
||||
found = false;
|
||||
for (i=0; i<active_tasks.size(); i++) {
|
||||
if (active_tasks[i]->slot == j) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) return j;
|
||||
}
|
||||
|
||||
for (i=0; i<(unsigned int)total_slots; i++) {
|
||||
if (!slot_status[i]) {
|
||||
free(slot_status);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
free(slot_status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,8 @@
|
|||
#include "speed_stats.h"
|
||||
#include "client_state.h"
|
||||
|
||||
#define SECONDS_PER_MONTH (SECONDS_PER_DAY*30)
|
||||
#define BENCHMARK_PERIOD (SECONDS_PER_DAY*30)
|
||||
// rerun CPU benchmarks this often (hardware may have been upgraded)
|
||||
|
||||
CLIENT_STATE gstate;
|
||||
|
||||
|
@ -183,12 +184,11 @@ int CLIENT_STATE::init() {
|
|||
}
|
||||
|
||||
// Returns true if time tests should be run
|
||||
// This is determined by seeing if the user passed the "-no_time_test"
|
||||
// flag or if it's been a month since we last checked time stats
|
||||
//
|
||||
bool CLIENT_STATE::should_run_time_tests() {
|
||||
return (
|
||||
difftime(time(0), (time_t)host_info.p_calculated) > SECONDS_PER_MONTH
|
||||
difftime(time(0), (time_t)host_info.p_calculated) > BENCHMARK_PERIOD
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -569,7 +569,7 @@ int CLIENT_STATE::parse_state_file() {
|
|||
} else if (match_tag(buf, "<active_task_set>")) {
|
||||
active_tasks.parse(f, this);
|
||||
} else if (match_tag(buf, "<platform_name>")) {
|
||||
// should match out current platform name
|
||||
// should match our current platform name
|
||||
} else if (match_tag(buf, "<version>")) {
|
||||
// could put logic here to detect incompatible state files
|
||||
// after core client update
|
||||
|
|
|
@ -37,6 +37,7 @@ PROJECT::PROJECT() {
|
|||
resource_share = 100;
|
||||
strcpy(project_name,"");
|
||||
strcpy(user_name,"");
|
||||
strcpy(team_name,"");
|
||||
user_total_credit = 0;
|
||||
user_expavg_credit = 0;
|
||||
user_create_time = 0;
|
||||
|
@ -103,6 +104,7 @@ int PROJECT::parse_state(FILE* in) {
|
|||
|
||||
strcpy(project_name, "");
|
||||
strcpy(user_name, "");
|
||||
strcpy(team_name, "");
|
||||
resource_share = 100;
|
||||
exp_avg_cpu = 0;
|
||||
exp_avg_mod_time = 0;
|
||||
|
@ -119,6 +121,7 @@ int PROJECT::parse_state(FILE* in) {
|
|||
else if (parse_str(buf, "<master_url>", master_url, sizeof(master_url))) continue;
|
||||
else if (parse_str(buf, "<project_name>", project_name, sizeof(project_name))) continue;
|
||||
else if (parse_str(buf, "<user_name>", user_name, sizeof(user_name))) continue;
|
||||
else if (parse_str(buf, "<team_name>", user_name, sizeof(team_name))) continue;
|
||||
else if (parse_double(buf, "<user_total_credit>", user_total_credit)) continue;
|
||||
else if (parse_double(buf, "<user_expavg_credit>", user_expavg_credit)) continue;
|
||||
else if (parse_int(buf, "<user_create_time>", (int &)user_create_time)) continue;
|
||||
|
@ -165,6 +168,7 @@ int PROJECT::write_state(FILE* out) {
|
|||
" <master_url>%s</master_url>\n"
|
||||
" <project_name>%s</project_name>\n"
|
||||
" <user_name>%s</user_name>\n"
|
||||
" <team_name>%s</team_name>\n"
|
||||
" <user_total_credit>%f</user_total_credit>\n"
|
||||
" <user_expavg_credit>%f</user_expavg_credit>\n"
|
||||
" <user_create_time>%d</user_create_time>\n"
|
||||
|
@ -181,6 +185,7 @@ int PROJECT::write_state(FILE* out) {
|
|||
master_url,
|
||||
project_name,
|
||||
user_name,
|
||||
team_name,
|
||||
user_total_credit,
|
||||
user_expavg_credit,
|
||||
user_create_time,
|
||||
|
@ -213,6 +218,7 @@ void PROJECT::copy_state_fields(PROJECT& p) {
|
|||
scheduler_urls = p.scheduler_urls;
|
||||
strcpy(project_name, p.project_name);
|
||||
strcpy(user_name, p.user_name);
|
||||
strcpy(team_name, p.team_name);
|
||||
user_total_credit = p.user_total_credit;
|
||||
user_expavg_credit = p.user_expavg_credit;
|
||||
user_create_time = p.user_create_time;
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
vector<STRING256> scheduler_urls; // where to find scheduling servers
|
||||
char project_name[256]; // descriptive. not unique
|
||||
char user_name[256];
|
||||
char team_name[256];
|
||||
double user_total_credit; // as reported by server
|
||||
double user_expavg_credit; // as reported by server
|
||||
unsigned int user_create_time; // as reported by server
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
// Contributor(s):
|
||||
//
|
||||
|
||||
// This file contains high-level logic for communicating with
|
||||
// scheduling servers,
|
||||
// High-level logic for communicating with scheduling servers,
|
||||
// and for merging the result of a scheduler RPC into the client state
|
||||
|
||||
// Note: code for actually doing a scheduler RPC is in scheduler_op.C
|
||||
|
@ -33,8 +32,9 @@
|
|||
#include "file_names.h"
|
||||
#include "filesys.h"
|
||||
#include "parse.h"
|
||||
#include "log_flags.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "log_flags.h"
|
||||
#include "account.h"
|
||||
#include "message.h"
|
||||
#include "scheduler_op.h"
|
||||
|
@ -43,8 +43,7 @@
|
|||
|
||||
// quantities like avg CPU time decay by a factor of e every week
|
||||
//
|
||||
#define SECONDS_IN_DAY (3600*24)
|
||||
#define EXP_DECAY_RATE (1./(SECONDS_IN_DAY*7))
|
||||
#define EXP_DECAY_RATE (1./(SECONDS_PER_DAY*7))
|
||||
|
||||
// estimate the days of work remaining
|
||||
//
|
||||
|
@ -60,7 +59,7 @@ double CLIENT_STATE::current_water_days() {
|
|||
// TODO: subtract time already finished for WUs in progress
|
||||
seconds_remaining += rp->wup->seconds_to_complete;
|
||||
}
|
||||
return (seconds_remaining / SECONDS_IN_DAY);
|
||||
return (seconds_remaining / SECONDS_PER_DAY);
|
||||
}
|
||||
|
||||
// seconds of work needed to come up to high-water mark
|
||||
|
@ -68,7 +67,7 @@ double CLIENT_STATE::current_water_days() {
|
|||
double CLIENT_STATE::work_needed_secs() {
|
||||
double x = current_water_days();
|
||||
if (x > global_prefs.high_water_days) return 0;
|
||||
return (global_prefs.high_water_days - x)*SECONDS_IN_DAY;
|
||||
return (global_prefs.high_water_days - x)*SECONDS_PER_DAY;
|
||||
}
|
||||
|
||||
// update exponentially-averaged CPU times of all projects
|
||||
|
|
|
@ -191,15 +191,14 @@ int HOST_INFO::write_time_tests(FILE* out) {
|
|||
}
|
||||
|
||||
// Returns the domain of the local host
|
||||
// TODO: Should the 256 be MAXHOSTNAMELEN instead?
|
||||
//
|
||||
int get_local_domain_name(char* p) {
|
||||
int get_local_domain_name(char* p, int len) {
|
||||
char buf[256];
|
||||
|
||||
gethostname(buf, 256);
|
||||
struct hostent* he = gethostbyname(buf);
|
||||
if (!he) return -1;
|
||||
strcpy(p, he->h_name);
|
||||
strncpy(p, he->h_name, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ extern int get_host_info(HOST_INFO&);
|
|||
extern void clear_host_info(HOST_INFO&);
|
||||
extern void get_host_disk_info( double &total_space, double &free_space );
|
||||
|
||||
extern int get_local_domain_name(char* p);
|
||||
extern int get_local_domain_name(char* p, int len);
|
||||
extern int get_local_ip_addr_str(char* p);
|
||||
extern int get_local_ip_addr(int& p);
|
||||
|
||||
|
|
|
@ -300,7 +300,7 @@ int get_host_info(HOST_INFO& host) {
|
|||
parse_meminfo(host);
|
||||
#endif
|
||||
|
||||
get_local_domain_name(host.domain_name);
|
||||
get_local_domain_name(host.domain_name, sizeof(host.domain_name));
|
||||
get_local_ip_addr_str(host.ip_addr);
|
||||
host.timezone = get_timezone();
|
||||
#ifdef HAVE_SYS_UTSNAME_H
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "parse.h"
|
||||
#include "util.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
#include "time_stats.h"
|
||||
|
@ -30,7 +31,7 @@
|
|||
// The last 30 days have a weight of 1/e;
|
||||
// everything before that has a weight of (1-1/e)
|
||||
|
||||
#define ALPHA (3600.*24*7*30)
|
||||
#define ALPHA (SECONDS_PER_DAY*30)
|
||||
|
||||
TIME_STATS::TIME_STATS() {
|
||||
last_update = 0;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
require_once("db.inc");
|
||||
require_once("util.inc");
|
||||
require_once("prefs.inc");
|
||||
|
||||
$authenticator = init_session();
|
||||
db_init();
|
||||
|
|
|
@ -15,10 +15,11 @@ if ($user == NULL) {
|
|||
|
||||
// TODO: consolidate the three DB updates into one
|
||||
|
||||
$prefs = prefs_parse($user->prefs);
|
||||
$prefs = prefs_parse($user->global_prefs);
|
||||
prefs_global_parse_form($prefs);
|
||||
global_prefs_update($user, $prefs);
|
||||
|
||||
$prefs = prefs_parse($user->project_prefs);
|
||||
prefs_email_parse_form($prefs);
|
||||
project_prefs_update($user, $prefs);
|
||||
|
||||
|
|
|
@ -14,10 +14,9 @@ function platform_downloads($platform, $core_app) {
|
|||
echo "CAN'T FIND FILENAMEn $app_version->xml_doc\n";
|
||||
}
|
||||
$version = sprintf(
|
||||
$platform->name,
|
||||
$app_version->version_num/100
|
||||
);
|
||||
echo "<tr><td><a href=$download_url/$filename><b>$platform->user_friendly_name</b></td></tr>\n";
|
||||
echo "<tr><td><a href=$download_url/$filename><b>$platform->user_friendly_name $version</b></td></tr>\n";
|
||||
//$app_version->md5_cksum";
|
||||
$found = true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,984 @@
|
|||
<?php
|
||||
/**
|
||||
* htmlfilter.inc
|
||||
* ---------------
|
||||
* This set of functions allows you to filter html in order to remove
|
||||
* any malicious tags from it. Useful in cases when you need to filter
|
||||
* user input for any cross-site-scripting attempts.
|
||||
*
|
||||
* Copyright (c) 2002 by Duke University
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* @Author Konstantin Riabitsev <icon@linux.duke.edu>
|
||||
* @Version 1.0.5 (Oct-16-2002)
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a debugging function used throughout the code. To enable
|
||||
* debugging you have to specify a global variable called "debug" before
|
||||
* calling sanitize() and set it to true.
|
||||
*
|
||||
* Note: Although insignificantly, debugging does slow you down even
|
||||
* when $debug is set to false. If you wish to get rid of all
|
||||
* debugging calls, run the following command:
|
||||
*
|
||||
* fgrep -v 'spew("' htmlfilter.inc > htmlfilter.inc.new
|
||||
*
|
||||
* htmlfilter.inc.new will contain no debugging calls.
|
||||
*
|
||||
* @param $message A string with the message to output.
|
||||
* @return void.
|
||||
*/
|
||||
function spew($message){
|
||||
global $debug;
|
||||
if ($debug == true){
|
||||
echo "$message";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the final tag out of the tag name, an array
|
||||
* of attributes, and the type of the tag. This function is called by
|
||||
* sanitize internally.
|
||||
*
|
||||
* @param $tagname the name of the tag.
|
||||
* @param $attary the array of attributes and their values
|
||||
* @param $tagtype The type of the tag (see in comments).
|
||||
* @return a string with the final tag representation.
|
||||
*/
|
||||
function tagprint($tagname, $attary, $tagtype){
|
||||
$me = 'tagprint';
|
||||
if ($tagtype == 2){
|
||||
$fulltag = '</' . $tagname . '>';
|
||||
} else {
|
||||
$fulltag = '<' . $tagname;
|
||||
if (is_array($attary) && sizeof($attary)){
|
||||
$atts = Array();
|
||||
while (list($attname, $attvalue) = each($attary)){
|
||||
array_push($atts, "$attname=$attvalue");
|
||||
}
|
||||
$fulltag .= ' ' . join(' ', $atts);
|
||||
}
|
||||
if ($tagtype == 3){
|
||||
$fulltag .= ' /';
|
||||
}
|
||||
$fulltag .= '>';
|
||||
}
|
||||
spew("$me: $fulltag\n");
|
||||
return $fulltag;
|
||||
}
|
||||
|
||||
/**
|
||||
* A small helper function to use with array_walk. Modifies a by-ref
|
||||
* value and makes it lowercase.
|
||||
*
|
||||
* @param $val a value passed by-ref.
|
||||
* @return void since it modifies a by-ref value.
|
||||
*/
|
||||
function casenormalize(&$val){
|
||||
$val = strtolower($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function skips any whitespace from the current position within
|
||||
* a string and to the next non-whitespace value.
|
||||
*
|
||||
* @param $body the string
|
||||
* @param $offset the offset within the string where we should start
|
||||
* looking for the next non-whitespace character.
|
||||
* @return the location within the $body where the next
|
||||
* non-whitespace char is located.
|
||||
*/
|
||||
function skipspace($body, $offset){
|
||||
$me = 'skipspace';
|
||||
preg_match('/^(\s*)/s', substr($body, $offset), $matches);
|
||||
if (sizeof($matches{1})){
|
||||
$count = strlen($matches{1});
|
||||
spew("$me: skipped $count chars\n");
|
||||
$offset += $count;
|
||||
}
|
||||
return $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function looks for the next character within a string. It's
|
||||
* really just a glorified "strpos", except it catches the failures
|
||||
* nicely.
|
||||
*
|
||||
* @param $body The string to look for needle in.
|
||||
* @param $offset Start looking from this position.
|
||||
* @param $needle The character/string to look for.
|
||||
* @return location of the next occurance of the needle, or
|
||||
* strlen($body) if needle wasn't found.
|
||||
*/
|
||||
function findnxstr($body, $offset, $needle){
|
||||
$me = 'findnxstr';
|
||||
$pos = strpos($body, $needle, $offset);
|
||||
if ($pos === FALSE){
|
||||
$pos = strlen($body);
|
||||
spew("$me: end of body reached\n");
|
||||
}
|
||||
spew("$me: '$needle' found at pos $pos\n");
|
||||
return $pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function takes a PCRE-style regexp and tries to match it
|
||||
* within the string.
|
||||
*
|
||||
* @param $body The string to look for needle in.
|
||||
* @param $offset Start looking from here.
|
||||
* @param $reg A PCRE-style regex to match.
|
||||
* @return Returns a false if no matches found, or an array
|
||||
* with the following members:
|
||||
* - integer with the location of the match within $body
|
||||
* - string with whatever content between offset and the match
|
||||
* - string with whatever it is we matched
|
||||
*/
|
||||
function findnxreg($body, $offset, $reg){
|
||||
$me = 'findnxreg';
|
||||
$matches = Array();
|
||||
$retarr = Array();
|
||||
$preg_rule = '%^(.*?)(' . $reg . ')%s';
|
||||
preg_match($preg_rule, substr($body, $offset), $matches);
|
||||
if (!$matches{0}){
|
||||
spew("$me: No matches found.\n");
|
||||
$retarr = false;
|
||||
} else {
|
||||
$retarr{0} = $offset + strlen($matches{1});
|
||||
$retarr{1} = $matches{1};
|
||||
$retarr{2} = $matches{2};
|
||||
spew("$me: '$reg' found at pos $offset matching '".$matches{2}."'\n");
|
||||
}
|
||||
return $retarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function looks for the next tag.
|
||||
*
|
||||
* @param $body String where to look for the next tag.
|
||||
* @param $offset Start looking from here.
|
||||
* @return false if no more tags exist in the body, or
|
||||
* an array with the following members:
|
||||
* - string with the name of the tag
|
||||
* - array with attributes and their values
|
||||
* - integer with tag type (1, 2, or 3)
|
||||
* - integer where the tag starts (starting "<")
|
||||
* - integer where the tag ends (ending ">")
|
||||
* first three members will be false, if the tag is invalid.
|
||||
*/
|
||||
function getnxtag($body, $offset){
|
||||
$me = 'getnxtag';
|
||||
if ($offset > strlen($body)){
|
||||
spew("$me: Past the end of body\n");
|
||||
return false;
|
||||
}
|
||||
$lt = findnxstr($body, $offset, '<');
|
||||
if ($lt == strlen($body)){
|
||||
spew("$me: No more tags found!\n");
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* We are here:
|
||||
* blah blah <tag attribute="value">
|
||||
* \---------^
|
||||
*/
|
||||
spew("$me: Found '<' at pos $lt\n");
|
||||
$pos = skipspace($body, $lt + 1);
|
||||
if ($pos >= strlen($body)){
|
||||
spew("$me: End of body reached.\n");
|
||||
return Array(false, false, false, $lt, strlen($body));
|
||||
}
|
||||
/**
|
||||
* There are 3 kinds of tags:
|
||||
* 1. Opening tag, e.g.:
|
||||
* <a href="blah">
|
||||
* 2. Closing tag, e.g.:
|
||||
* </a>
|
||||
* 3. XHTML-style content-less tag, e.g.:
|
||||
* <img src="blah"/>
|
||||
*/
|
||||
$tagtype = false;
|
||||
switch (substr($body, $pos, 1)){
|
||||
case '/':
|
||||
spew("$me: This is a closing tag (type 2)\n");
|
||||
$tagtype = 2;
|
||||
$pos++;
|
||||
break;
|
||||
case '!':
|
||||
/**
|
||||
* A comment or an SGML declaration.
|
||||
*/
|
||||
if (substr($body, $pos+1, 2) == '--'){
|
||||
spew("$me: A comment found. Stripping.\n");
|
||||
$gt = strpos($body, '-->', $pos);
|
||||
if ($gt === false){
|
||||
$gt = strlen($body);
|
||||
} else {
|
||||
$gt += 2;
|
||||
}
|
||||
return Array(false, false, false, $lt, $gt);
|
||||
} else {
|
||||
spew("$me: An SGML declaration found. Stripping.\n");
|
||||
$gt = findnxstr($body, $pos, '>');
|
||||
return Array(false, false, false, $lt, $gt);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/**
|
||||
* Assume tagtype 1 for now. If it's type 3, we'll switch values
|
||||
* later.
|
||||
*/
|
||||
$tagtype = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
$tag_start = $pos;
|
||||
$tagname = '';
|
||||
/**
|
||||
* Look for next [\W-_], which will indicate the end of the tag name.
|
||||
*/
|
||||
$regary = findnxreg($body, $pos, '[^\w\-_]');
|
||||
if ($regary == false){
|
||||
spew("$me: End of body reached while analyzing tag name\n");
|
||||
return Array(false, false, false, $lt, strlen($body));
|
||||
}
|
||||
list($pos, $tagname, $match) = $regary;
|
||||
$tagname = strtolower($tagname);
|
||||
|
||||
/**
|
||||
* $match can be either of these:
|
||||
* '>' indicating the end of the tag entirely.
|
||||
* '\s' indicating the end of the tag name.
|
||||
* '/' indicating that this is type-3 xhtml tag.
|
||||
*
|
||||
* Whatever else we find there indicates an invalid tag.
|
||||
*/
|
||||
switch ($match){
|
||||
case '/':
|
||||
/**
|
||||
* This is an xhtml-style tag with a closing / at the
|
||||
* end, like so: <img src="blah"/>. Check if it's followed
|
||||
* by the closing bracket. If not, then this tag is invalid
|
||||
*/
|
||||
if (substr($body, $pos, 2) == '/>'){
|
||||
spew("$me: XHTML-style tag found.\n");
|
||||
$pos++;
|
||||
spew("$me: Setting tagtype to 3\n");
|
||||
$tagtype = 3;
|
||||
} else {
|
||||
spew("$me: Found invalid character '/'.\n");
|
||||
$gt = findnxstr($body, $pos, '>');
|
||||
spew("$me: Tag is invalid. Returning.\n");
|
||||
$retary = Array(false, false, false, $lt, $gt);
|
||||
return $retary;
|
||||
}
|
||||
case '>':
|
||||
spew("$me: End of tag found at $pos\n");
|
||||
spew("$me: Tagname is '$tagname'\n");
|
||||
spew("$me: This tag has no attributes\n");
|
||||
return Array($tagname, false, $tagtype, $lt, $pos);
|
||||
break;
|
||||
default:
|
||||
/**
|
||||
* Check if it's whitespace
|
||||
*/
|
||||
if (preg_match('/\s/', $match)){
|
||||
spew("$me: Tagname is '$tagname'\n");
|
||||
} else {
|
||||
/**
|
||||
* This is an invalid tag! Look for the next closing ">".
|
||||
*/
|
||||
spew("$me: Invalid characters found in tag name: $match\n");
|
||||
$gt = findnxstr($body, $offset, '>');
|
||||
return Array(false, false, false, $lt, $gt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At this point we're here:
|
||||
* <tagname attribute='blah'>
|
||||
* \-------^
|
||||
*
|
||||
* At this point we loop in order to find all attributes.
|
||||
*/
|
||||
$attname = '';
|
||||
$atttype = false;
|
||||
$attary = Array();
|
||||
|
||||
while ($pos <= strlen($body)){
|
||||
$pos = skipspace($body, $pos);
|
||||
if ($pos == strlen($body)){
|
||||
/**
|
||||
* Non-closed tag.
|
||||
*/
|
||||
spew("$me: End of body reached before end of tag. Discarding.\n");
|
||||
return Array(false, false, false, $lt, $pos);
|
||||
}
|
||||
/**
|
||||
* See if we arrived at a ">" or "/>", which means that we reached
|
||||
* the end of the tag.
|
||||
*/
|
||||
$matches = Array();
|
||||
preg_match('%^(\s*)(>|/>)%s', substr($body, $pos), $matches);
|
||||
if (isset($matches{0}) && $matches{0}){
|
||||
/**
|
||||
* Yep. So we did.
|
||||
*/
|
||||
spew("$me: Arrived at the end of the tag.\n");
|
||||
$pos += strlen($matches{1});
|
||||
if ($matches{2} == '/>'){
|
||||
$tagtype = 3;
|
||||
$pos++;
|
||||
}
|
||||
return Array($tagname, $attary, $tagtype, $lt, $pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* There are several types of attributes, with optional
|
||||
* [:space:] between members.
|
||||
* Type 1:
|
||||
* attrname[:space:]=[:space:]'CDATA'
|
||||
* Type 2:
|
||||
* attrname[:space:]=[:space:]"CDATA"
|
||||
* Type 3:
|
||||
* attr[:space:]=[:space:]CDATA
|
||||
* Type 4:
|
||||
* attrname
|
||||
*
|
||||
* We leave types 1 and 2 the same, type 3 we check for
|
||||
* '"' and convert to """ if needed, then wrap in
|
||||
* double quotes. Type 4 we convert into:
|
||||
* attrname="yes".
|
||||
*/
|
||||
$regary = findnxreg($body, $pos, '[^\w\-_]');
|
||||
if ($regary == false){
|
||||
/**
|
||||
* Looks like body ended before the end of tag.
|
||||
*/
|
||||
spew("$me: End of body found before end of tag.\n");
|
||||
spew("$me: Invalid, returning\n");
|
||||
return Array(false, false, false, $lt, strlen($body));
|
||||
}
|
||||
list($pos, $attname, $match) = $regary;
|
||||
$attname = strtolower($attname);
|
||||
spew("$me: Attribute '$attname' found\n");
|
||||
/**
|
||||
* We arrived at the end of attribute name. Several things possible
|
||||
* here:
|
||||
* '>' means the end of the tag and this is attribute type 4
|
||||
* '/' if followed by '>' means the same thing as above
|
||||
* '\s' means a lot of things -- look what it's followed by.
|
||||
* anything else means the attribute is invalid.
|
||||
*/
|
||||
switch($match){
|
||||
case '/':
|
||||
/**
|
||||
* This is an xhtml-style tag with a closing / at the
|
||||
* end, like so: <img src="blah"/>. Check if it's followed
|
||||
* by the closing bracket. If not, then this tag is invalid
|
||||
*/
|
||||
if (substr($body, $pos, 2) == '/>'){
|
||||
spew("$me: This is an xhtml-style tag.\n");
|
||||
$pos++;
|
||||
spew("$me: Setting tagtype to 3\n");
|
||||
$tagtype = 3;
|
||||
} else {
|
||||
spew("$me: Found invalid character '/'.\n");
|
||||
$gt = findnxstr($body, $pos, '>');
|
||||
spew("$me: Tag is invalid. Returning.\n");
|
||||
$retary = Array(false, false, false, $lt, $gt);
|
||||
return $retary;
|
||||
}
|
||||
case '>':
|
||||
spew("$me: found type 4 attribute.\n");
|
||||
spew("$me: Additionally, end of tag found at $pos\n");
|
||||
spew("$me: Attname is '$attname'\n");
|
||||
spew("$me: Setting attvalue to 'yes'\n");
|
||||
$attary{$attname} = '"yes"';
|
||||
return Array($tagname, $attary, $tagtype, $lt, $pos);
|
||||
break;
|
||||
default:
|
||||
/**
|
||||
* Skip whitespace and see what we arrive at.
|
||||
*/
|
||||
$pos = skipspace($body, $pos);
|
||||
$char = substr($body, $pos, 1);
|
||||
/**
|
||||
* Two things are valid here:
|
||||
* '=' means this is attribute type 1 2 or 3.
|
||||
* \w means this was attribute type 4.
|
||||
* anything else we ignore and re-loop. End of tag and
|
||||
* invalid stuff will be caught by our checks at the beginning
|
||||
* of the loop.
|
||||
*/
|
||||
if ($char == '='){
|
||||
spew("$me: Attribute type 1, 2, or 3 found.\n");
|
||||
$pos++;
|
||||
$pos = skipspace($body, $pos);
|
||||
/**
|
||||
* Here are 3 possibilities:
|
||||
* "'" attribute type 1
|
||||
* '"' attribute type 2
|
||||
* everything else is the content of tag type 3
|
||||
*/
|
||||
$quot = substr($body, $pos, 1);
|
||||
if ($quot == '\''){
|
||||
spew("$me: In fact, this is attribute type 1\n");
|
||||
spew("$me: looking for closing quote\n");
|
||||
$regary = findnxreg($body, $pos+1, '\'');
|
||||
if ($regary == false){
|
||||
spew("$me: end of body reached before end of val\n");
|
||||
spew("$me: Returning\n");
|
||||
return Array(false, false, false, $lt, strlen($body));
|
||||
}
|
||||
list($pos, $attval, $match) = $regary;
|
||||
spew("$me: Attvalue is '$attval'\n");
|
||||
$pos++;
|
||||
$attary{$attname} = '\'' . $attval . '\'';
|
||||
} else if ($quot == '"'){
|
||||
spew("$me: In fact, this is attribute type 2\n");
|
||||
spew("$me: looking for closing quote\n");
|
||||
$regary = findnxreg($body, $pos+1, '\"');
|
||||
if ($regary == false){
|
||||
spew("$me: end of body reached before end of val\n");
|
||||
spew("$me: Returning\n");
|
||||
return Array(false, false, false, $lt, strlen($body));
|
||||
}
|
||||
list($pos, $attval, $match) = $regary;
|
||||
spew("$me: Attvalue is \"$attval\"\n");
|
||||
$pos++;
|
||||
$attary{$attname} = '"' . $attval . '"';
|
||||
} else {
|
||||
spew("$me: This looks like attribute type 3\n");
|
||||
/**
|
||||
* These are hateful. Look for \s, or >.
|
||||
*/
|
||||
spew("$me: Looking for end of attval\n");
|
||||
$regary = findnxreg($body, $pos, '[\s>]');
|
||||
if ($regary == false){
|
||||
spew("$me: end of body reached before end of val\n");
|
||||
spew("$me: Returning\n");
|
||||
return Array(false, false, false, $lt, strlen($body));
|
||||
}
|
||||
list($pos, $attval, $match) = $regary;
|
||||
/**
|
||||
* If it's ">" it will be caught at the top.
|
||||
*/
|
||||
spew("$me: translating '\"' into "\n");
|
||||
$attval = preg_replace('/\"/s', '"', $attval);
|
||||
spew("$me: wrapping in quotes\n");
|
||||
$attary{$attname} = '"' . $attval . '"';
|
||||
}
|
||||
} else if (preg_match('|[\w/>]|', $char)) {
|
||||
/**
|
||||
* That was attribute type 4.
|
||||
*/
|
||||
spew("$me: attribute type 4 found.\n");
|
||||
spew("$me: Setting value to 'yes'\n");
|
||||
$attary{$attname} = '"yes"';
|
||||
} else {
|
||||
/**
|
||||
* An illegal character. Find next '>' and return.
|
||||
*/
|
||||
spew("$me: illegal character '$char' found.\n");
|
||||
spew("$me: returning\n");
|
||||
$gt = findnxstr($body, $pos, '>');
|
||||
return Array(false, false, false, $lt, $gt);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The fact that we got here indicates that the tag end was never
|
||||
* found. Return invalid tag indication so it gets stripped.
|
||||
*/
|
||||
spew("$me: No tag end found\n");
|
||||
return Array(false, false, false, $lt, strlen($body));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks attribute values for entity-encoded values
|
||||
* and returns them translated into 8-bit strings so we can run
|
||||
* checks on them.
|
||||
*
|
||||
* @param $attvalue A string to run entity check against.
|
||||
* @return Translated value.
|
||||
*/
|
||||
function deent($attvalue){
|
||||
$me = 'deent';
|
||||
/**
|
||||
* See if we have to run the checks first. All entities must start
|
||||
* with "&".
|
||||
*/
|
||||
if (strpos($attvalue, '&') === false){
|
||||
return $attvalue;
|
||||
}
|
||||
/**
|
||||
* Check named entities first.
|
||||
*/
|
||||
spew("$me: translating named entities\n");
|
||||
$trans = get_html_translation_table(HTML_ENTITIES);
|
||||
/**
|
||||
* Leave " in, as it can mess us up.
|
||||
*/
|
||||
$trans = array_flip($trans);
|
||||
unset($trans{'"'});
|
||||
while (list($ent, $val) = each($trans)){
|
||||
$attvalue = preg_replace('/' . $ent . '*/si', $val, $attvalue);
|
||||
}
|
||||
/**
|
||||
* Now translate numbered entities from 1 to 255 if needed.
|
||||
*/
|
||||
if (strpos($attvalue, '#') !== false){
|
||||
spew("$me: translating numbered entities\n");
|
||||
$omit = Array(34, 39);
|
||||
for ($asc = 256; $asc >= 0; $asc--){
|
||||
if (!in_array($asc, $omit)){
|
||||
$chr = chr($asc);
|
||||
$octrule = '/\�*' . $asc . ';*/si';
|
||||
$hexrule = '/\�*' . dechex($asc) . ';*/si';
|
||||
$attvalue = preg_replace($octrule, $chr, $attvalue);
|
||||
$attvalue = preg_replace($hexrule, $chr, $attvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
spew("$me: translated into: $attvalue\n");
|
||||
return $attvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function runs various checks against the attributes.
|
||||
*
|
||||
* @param $tagname String with the name of the tag.
|
||||
* @param $attary Array with all tag attributes.
|
||||
* @param $rm_attnames See description for sanitize
|
||||
* @param $bad_attvals See description for sanitize
|
||||
* @param $add_attr_to_tag See description for sanitize
|
||||
* @return Array with modified attributes.
|
||||
*/
|
||||
function fixatts($tagname,
|
||||
$attary,
|
||||
$rm_attnames,
|
||||
$bad_attvals,
|
||||
$add_attr_to_tag
|
||||
){
|
||||
$me = 'fixatts';
|
||||
spew("$me: Fixing attributes\n");
|
||||
while (list($attname, $attvalue) = each($attary)){
|
||||
/**
|
||||
* See if this attribute should be removed.
|
||||
*/
|
||||
foreach ($rm_attnames as $matchtag=>$matchattrs){
|
||||
if (preg_match($matchtag, $tagname)){
|
||||
foreach ($matchattrs as $matchattr){
|
||||
if (preg_match($matchattr, $attname)){
|
||||
spew("$me: Attribute '$attname' defined as bad.\n");
|
||||
spew("$me: Removing.\n");
|
||||
unset($attary{$attname});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove any entities.
|
||||
*/
|
||||
$attvalue = deent($attvalue);
|
||||
|
||||
/**
|
||||
* Now let's run checks on the attvalues.
|
||||
* I don't expect anyone to comprehend this. If you do,
|
||||
* get in touch with me so I can drive to where you live and
|
||||
* shake your hand personally. :)
|
||||
*/
|
||||
foreach ($bad_attvals as $matchtag=>$matchattrs){
|
||||
if (preg_match($matchtag, $tagname)){
|
||||
foreach ($matchattrs as $matchattr=>$valary){
|
||||
if (preg_match($matchattr, $attname)){
|
||||
/**
|
||||
* There are two arrays in valary.
|
||||
* First is matches.
|
||||
* Second one is replacements
|
||||
*/
|
||||
list($valmatch, $valrepl) = $valary;
|
||||
$newvalue = preg_replace($valmatch, $valrepl, $attvalue);
|
||||
if ($newvalue != $attvalue){
|
||||
spew("$me: attvalue is now $newvalue\n");
|
||||
$attary{$attname} = $newvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* See if we need to append any attributes to this tag.
|
||||
*/
|
||||
foreach ($add_attr_to_tag as $matchtag=>$addattary){
|
||||
if (preg_match($matchtag, $tagname)){
|
||||
$attary = array_merge($attary, $addattary);
|
||||
spew("$me: Added attributes to this tag\n");
|
||||
}
|
||||
}
|
||||
return $attary;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main function and the one you should actually be calling.
|
||||
* There are several variables you should be aware of an which need
|
||||
* special description.
|
||||
*
|
||||
* $tag_list
|
||||
* ----------
|
||||
* This is a simple one-dimentional array of strings, except for the
|
||||
* very first one. The first member should be einter false or true.
|
||||
* In case it's FALSE, the following list will be considered a list of
|
||||
* tags that should be explicitly REMOVED from the body, and all
|
||||
* others that did not match the list will be allowed. If the first
|
||||
* member is TRUE, then the list is the list of tags that should be
|
||||
* explicitly ALLOWED -- any tag not matching this list will be
|
||||
* discarded.
|
||||
*
|
||||
* Examples:
|
||||
* $tag_list = Array(
|
||||
* false,
|
||||
* "blink",
|
||||
* "link",
|
||||
* "object",
|
||||
* "meta",
|
||||
* "marquee",
|
||||
* "html"
|
||||
* );
|
||||
*
|
||||
* This will allow all tags except for blink, link, object, meta, marquee,
|
||||
* and html.
|
||||
*
|
||||
* $tag_list = Array(
|
||||
* true,
|
||||
* "b",
|
||||
* "a",
|
||||
* "i",
|
||||
* "img",
|
||||
* "strong",
|
||||
* "em",
|
||||
* "p"
|
||||
* );
|
||||
*
|
||||
* This will remove all tags from the body except b, a, i, img, strong, em and
|
||||
* p.
|
||||
*
|
||||
* $rm_tags_with_content
|
||||
* ---------------------
|
||||
* This is a simple one-dimentional array of strings, which specifies the
|
||||
* tags to be removed with any and all content between the beginning and
|
||||
* the end of the tag.
|
||||
* Example:
|
||||
* $rm_tags_with_content = Array(
|
||||
* "script",
|
||||
* "style",
|
||||
* "applet",
|
||||
* "embed"
|
||||
* );
|
||||
*
|
||||
* This will remove the following structure:
|
||||
* <script>
|
||||
* window.alert("Isn't cross-site-scripting fun?!");
|
||||
* </script>
|
||||
*
|
||||
* $self_closing_tags
|
||||
* ------------------
|
||||
* This is a simple one-dimentional array of strings, which specifies which
|
||||
* tags contain no content and should not be forcefully closed if this option
|
||||
* is turned on (see further).
|
||||
* Example:
|
||||
* $self_closing_tags = Array(
|
||||
* "img",
|
||||
* "br",
|
||||
* "hr",
|
||||
* "input"
|
||||
* );
|
||||
*
|
||||
* $force_tag_closing
|
||||
* ------------------
|
||||
* Set it to true to forcefully close any tags opened within the document.
|
||||
* This is good if you want to take care of people who like to screw up
|
||||
* the pages by leaving unclosed tags like <a>, <b>, <i>, etc.
|
||||
*
|
||||
* $rm_attnames
|
||||
* -------------
|
||||
* Now we come to parameters that are more obscure. This parameter is
|
||||
* a nested array which is used to specify which attributes should be
|
||||
* removed. It goes like so:
|
||||
*
|
||||
* $rm_attnames = Array(
|
||||
* "PCRE regex to match tag name" =>
|
||||
* Array(
|
||||
* "PCRE regex to match attribute name"
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* Example:
|
||||
* $rm_attnames = Array(
|
||||
* "|.*|" =>
|
||||
* Array(
|
||||
* "|target|i",
|
||||
* "|^on.*|i"
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* This will match all attributes (.*), and specify that all attributes
|
||||
* named "target" and starting with "on" should be removed. This will take
|
||||
* care of the following problem:
|
||||
* <em onmouseover="window.alert('muahahahaha')">
|
||||
* The "onmouseover" will be removed.
|
||||
*
|
||||
* $bad_attvals
|
||||
* ------------
|
||||
* This is where it gets ugly. This is a nested array with many levels.
|
||||
* It goes like so:
|
||||
*
|
||||
* $bad_attvals = Array(
|
||||
* "pcre regex to match tag name" =>
|
||||
* Array(
|
||||
* "pcre regex to match attribute name" =>
|
||||
* Array(
|
||||
* "pcre regex to match attribute value"
|
||||
* )
|
||||
* Array(
|
||||
* "pcre regex replace a match from above with"
|
||||
* )
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* An extensive example:
|
||||
*
|
||||
* $bad_attvals = Array(
|
||||
* "|.*|" =>
|
||||
* Array(
|
||||
* "/^src|background|href|action/i" =>
|
||||
* Array(
|
||||
* Array(
|
||||
* "/^([\'\"])\s*\S+script\s*:.*([\'\"])/si"
|
||||
* ),
|
||||
* Array(
|
||||
* "\\1http://veryfunny.com/\\2"
|
||||
* )
|
||||
* ),
|
||||
* "/^style/i" =>
|
||||
* Array(
|
||||
* Array(
|
||||
* "/expression/si",
|
||||
* "/url\(([\'\"])\s*https*:.*([\'\"])\)/si",
|
||||
* "/url\(([\'\"])\s*\S+script:.*([\'\"])\)/si"
|
||||
* ),
|
||||
* Array(
|
||||
* "idiocy",
|
||||
* "url(\\1http://veryfunny.com/\\2)",
|
||||
* "url(\\1http://veryfynny.com/\\2)"
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* This will take care of nearly all known cross-site scripting exploits,
|
||||
* plus some (see my filter sample at
|
||||
* http://www.mricon.com/html/phpfilter.html for a working version).
|
||||
*
|
||||
* $add_attr_to_tag
|
||||
* ----------------
|
||||
* This is a useful little feature which lets you add attributes to
|
||||
* certain tags. It is a nested array as well, but not at all like
|
||||
* the previous one. It goes like so:
|
||||
*
|
||||
* $add_attr_to_tag = Array(
|
||||
* "PCRE regex to match tag name" =>
|
||||
* Array(
|
||||
* "attribute name"=>'"attribute value"'
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* Note: don't forget quotes around attribute value.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $add_attr_to_tag = Array(
|
||||
* "/^a$/si" =>
|
||||
* Array(
|
||||
* 'target'=>'"_new"'
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* This will change all <a> tags and add target="_new" to them so all links
|
||||
* open in a new window.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param $body the string with HTML you wish to filter
|
||||
* @param $tag_list see description above
|
||||
* @param $rm_tags_with_content see description above
|
||||
* @param $self_closing_tags see description above
|
||||
* @param $force_tag_closing see description above
|
||||
* @param $rm_attnames see description above
|
||||
* @param $bad_attvals see description above
|
||||
* @param $add_attr_to_tag see description above
|
||||
* @return sanitized html safe to show on your pages.
|
||||
*/
|
||||
function sanitize($body,
|
||||
$tag_list,
|
||||
$rm_tags_with_content,
|
||||
$self_closing_tags,
|
||||
$force_tag_closing,
|
||||
$rm_attnames,
|
||||
$bad_attvals,
|
||||
$add_attr_to_tag
|
||||
){
|
||||
$me = 'sanitize';
|
||||
/**
|
||||
* Normalize rm_tags and rm_tags_with_content.
|
||||
*/
|
||||
@array_walk($rm_tags, 'casenormalize');
|
||||
@array_walk($rm_tags_with_content, 'casenormalize');
|
||||
@array_walk($self_closing_tags, 'casenormalize');
|
||||
/**
|
||||
* See if tag_list is of tags to remove or tags to allow.
|
||||
* false means remove these tags
|
||||
* true means allow these tags
|
||||
*/
|
||||
$rm_tags = array_shift($tag_list);
|
||||
$curpos = 0;
|
||||
$open_tags = Array();
|
||||
$trusted = "<!-- begin sanitized html -->\n";
|
||||
$skip_content = false;
|
||||
/**
|
||||
* Take care of netscape's stupid javascript entities like
|
||||
* &{alert('boo')};
|
||||
*/
|
||||
$body = preg_replace('/&(\{.*?\};)/si', '&\\1', $body);
|
||||
spew("$me: invoking the loop\n");
|
||||
while (($curtag = getnxtag($body, $curpos)) != FALSE){
|
||||
list($tagname, $attary, $tagtype, $lt, $gt) = $curtag;
|
||||
spew("$me: grabbing free-standing content\n");
|
||||
$free_content = substr($body, $curpos, $lt - $curpos);
|
||||
spew("$me: " . strlen($free_content) . " chars grabbed\n");
|
||||
if ($skip_content == false){
|
||||
spew("$me: appending free content to trusted.\n");
|
||||
$trusted .= $free_content;
|
||||
} else {
|
||||
spew("$me: Skipping free content.\n");
|
||||
}
|
||||
if ($tagname != FALSE){
|
||||
spew("$me: tagname is '$tagname'\n");
|
||||
if ($tagtype == 2){
|
||||
spew("$me: This is a closing tag\n");
|
||||
if ($skip_content == $tagname){
|
||||
/**
|
||||
* Got to the end of tag we needed to remove.
|
||||
*/
|
||||
spew("$me: Finished removing tag with content\n");
|
||||
$tagname = false;
|
||||
$skip_content = false;
|
||||
} else {
|
||||
if ($skip_content == false){
|
||||
if (isset($open_tags{$tagname}) &&
|
||||
$open_tags{$tagname} > 0){
|
||||
spew("$me: popping '$tagname' from open_tags\n");
|
||||
$open_tags{$tagname}--;
|
||||
} else {
|
||||
spew("$me: '$tagname' was never opened\n");
|
||||
spew("$me: removing\n");
|
||||
$tagname = false;
|
||||
}
|
||||
} else {
|
||||
spew("$me: Skipping this tag\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* $rm_tags_with_content
|
||||
*/
|
||||
if ($skip_content == false){
|
||||
/**
|
||||
* See if this is a self-closing type and change
|
||||
* tagtype appropriately.
|
||||
*/
|
||||
if ($tagtype == 1
|
||||
&& in_array($tagname, $self_closing_tags)){
|
||||
spew("$me: Self-closing tag. Changing tagtype.\n");
|
||||
$tagtype = 3;
|
||||
}
|
||||
/**
|
||||
* See if we should skip this tag and any content
|
||||
* inside it.
|
||||
*/
|
||||
if ($tagtype == 1 && in_array($tagname, $rm_tags_with_content)){
|
||||
spew("$me: removing this tag with content\n");
|
||||
$skip_content = $tagname;
|
||||
} else {
|
||||
if (($rm_tags == false && in_array($tagname, $tag_list)) ||
|
||||
($rm_tags == true && !in_array($tagname, $tag_list))){
|
||||
spew("$me: Removing this tag.\n");
|
||||
$tagname = false;
|
||||
} else {
|
||||
if ($tagtype == 1){
|
||||
spew("$me: adding '$tagname' to open_tags\n");
|
||||
if (isset($open_tags{$tagname})){
|
||||
$open_tags{$tagname}++;
|
||||
} else {
|
||||
$open_tags{$tagname} = 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This is where we run other checks.
|
||||
*/
|
||||
if (is_array($attary) && sizeof($attary) > 0){
|
||||
$attary = fixatts($tagname,
|
||||
$attary,
|
||||
$rm_attnames,
|
||||
$bad_attvals,
|
||||
$add_attr_to_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
spew("$me: Skipping this tag\n");
|
||||
}
|
||||
}
|
||||
if ($tagname != false && $skip_content == false){
|
||||
spew("$me: Appending tag to trusted.\n");
|
||||
$trusted .= tagprint($tagname, $attary, $tagtype);
|
||||
}
|
||||
} else {
|
||||
spew("$me: Removing invalid tag\n");
|
||||
}
|
||||
$curpos = $gt + 1;
|
||||
}
|
||||
spew("$me: Appending any leftover content\n");
|
||||
$trusted .= substr($body, $curpos, strlen($body) - $curpos);
|
||||
if ($force_tag_closing == true){
|
||||
foreach ($open_tags as $tagname=>$opentimes){
|
||||
while ($opentimes > 0){
|
||||
spew("$me: '$tagname' left open. Closing by force.\n");
|
||||
$trusted .= '</' . $tagname . '>';
|
||||
$opentimes--;
|
||||
}
|
||||
}
|
||||
$trusted .= "\n";
|
||||
}
|
||||
$trusted .= "<!-- end sanitized html -->\n";
|
||||
return $trusted;
|
||||
}
|
||||
?>
|
|
@ -76,7 +76,7 @@ function element_end($parser, $name) {
|
|||
$parse_result->run_if_user_active = true;
|
||||
break;
|
||||
case "confirm_before_connecting":
|
||||
$parse_result->confirm_before_connecting = 1;
|
||||
$parse_result->confirm_before_connecting = true;
|
||||
break;
|
||||
case "low_water_days":
|
||||
$parse_result->low_water_days = $text;
|
||||
|
@ -128,8 +128,8 @@ function char_handler($parser, $x) {
|
|||
function default_prefs() {
|
||||
$p = null;
|
||||
$p->run_on_batteries = false;
|
||||
$p->run_if_user_active = false;
|
||||
$p->confirm_before_connecting = 0;
|
||||
$p->run_if_user_active = true;
|
||||
$p->confirm_before_connecting = false;
|
||||
$p->low_water_days = 1;
|
||||
$p->high_water_days = 3;
|
||||
$p->disk_max_used_gb = 100;
|
||||
|
@ -139,15 +139,18 @@ function default_prefs() {
|
|||
$p->resource_share = 100;
|
||||
$p->show_email = false;
|
||||
$p->send_email = true;
|
||||
|
||||
$p->project_specific = project_specific_prefs_default();
|
||||
return $p;
|
||||
}
|
||||
|
||||
// state of prefs before parsing
|
||||
//
|
||||
function initial_prefs() {
|
||||
$p = default_prefs;
|
||||
$p = default_prefs();
|
||||
$p->show_email = false;
|
||||
$p->send_email = false;
|
||||
return $p;
|
||||
}
|
||||
|
||||
// parse prefs (either global or project) from XML to a struct
|
||||
|
@ -242,8 +245,8 @@ function prefs_form_global($user, $prefs) {
|
|||
<br><font size=-1>(This matters only if you use a modem)</font>
|
||||
</td><td valign=top>
|
||||
";
|
||||
printf("Yes <input type=radio name=confirm_before_connecting %s>\n", $prefs->confirm_before_connecting?"checked":"");
|
||||
printf("No <input type=radio name=confirm_before_connecting %s>\n", $prefs->confirm_before_connecting?"":"checked");
|
||||
printf("Yes <input type=radio name=confirm_before_connecting value=yes %s>\n", $prefs->confirm_before_connecting?"checked":"");
|
||||
printf("No <input type=radio name=confirm_before_connecting value=no %s>\n", $prefs->confirm_before_connecting?"":"checked");
|
||||
echo "</td></tr>
|
||||
<tr>
|
||||
<td align=right>Keep enough to work on disk to last between
|
||||
|
@ -339,11 +342,21 @@ function venue_update($user) {
|
|||
//
|
||||
function prefs_global_parse_form(&$prefs) {
|
||||
parse_str(getenv("QUERY_STRING"));
|
||||
|
||||
$prefs->run_on_batteries = ($run_on_batteries == "yes");
|
||||
$prefs->run_if_user_active = ($run_if_user_active == "yes");
|
||||
$prefs->confirm_before_connecting = isset($confirm_before_connecting)?1:0;
|
||||
$prefs->confirm_before_connecting = ($confirm_before_connecting == "yes");
|
||||
|
||||
if ($low_water_days<0) $low_water_days = 0;
|
||||
if ($high_water_days<0) $high_water_days = 0;
|
||||
if ($low_water_days > $high_water_days) $low_water_days = $high_water_days;
|
||||
$prefs->low_water_days = $low_water_days;
|
||||
$prefs->high_water_days = $high_water_days;
|
||||
|
||||
if ($disk_max_used_gb<0) $disk_max_used_gb = 0;
|
||||
if ($disk_max_used_pct<0) $disk_max_used_pct = 0;
|
||||
if ($disk_max_used_pct>100) $disk_max_used_pct = 100;
|
||||
if ($disk_min_free_gb<0) $disk_min_free_gb = 0;
|
||||
$prefs->disk_max_used_gb = $disk_max_used_gb;
|
||||
$prefs->disk_max_used_pct = $disk_max_used_pct;
|
||||
$prefs->disk_min_free_gb = $disk_min_free_gb;
|
||||
|
@ -401,9 +414,14 @@ function project_prefs_make_xml($prefs) {
|
|||
if ($prefs->send_email == 1) {
|
||||
$xml = $xml."<send_email/>\n";
|
||||
}
|
||||
$xml = $xml
|
||||
."<resource_share>$prefs->resource_share</resource_share>\n"
|
||||
."<project_specific>\n$prefs->project_specific</project_specific>\n";
|
||||
if ($prefs->resource_share) {
|
||||
$xml = $xml
|
||||
."<resource_share>$prefs->resource_share</resource_share>\n";
|
||||
}
|
||||
if ($prefs->project_specific) {
|
||||
$xml = $xml
|
||||
."<project_specific>\n$prefs->project_specific</project_specific>\n";
|
||||
}
|
||||
$xml = $xml."</project_preferences>\n";
|
||||
return $xml;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
// This is a sample project file. Replace it with your own.
|
||||
|
||||
define("PROJECT", "Astropulse");
|
||||
define("MASTER_URL", "http://maggie.ssl.berkeley.edu/ap/");
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@ function option($name, $val) {
|
|||
echo "<option name='$name' $x>$name\n";
|
||||
}
|
||||
|
||||
function project_specific_prefs_default() {
|
||||
return "<color_scheme>Tahiti Sunset</color_scheme>\n";
|
||||
}
|
||||
|
||||
// given struct, show form for editing
|
||||
//
|
||||
function project_specific_prefs_edit($prefs) {
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
include_once("htmlfilter.inc");
|
||||
|
||||
// $tag_list = Array( false, 'blink', 'object', 'meta', 'font', 'html', 'link', 'frame', 'iframe', 'layer', 'ilayer');
|
||||
|
||||
$tag_list = Array(true, "b", "a", "i", "img", "strong", "em", "p");
|
||||
|
||||
$rm_tags_with_content = Array(
|
||||
'script',
|
||||
'style',
|
||||
'applet',
|
||||
'embed',
|
||||
'head',
|
||||
'frameset'
|
||||
);
|
||||
|
||||
$self_closing_tags = Array(
|
||||
'img',
|
||||
'br',
|
||||
'hr',
|
||||
'input'
|
||||
);
|
||||
|
||||
$force_tag_closing = false;
|
||||
|
||||
$rm_attnames = Array(
|
||||
'/.*/' =>
|
||||
Array(
|
||||
'/target/i',
|
||||
'/^on.*/i',
|
||||
'/^dynsrc/i',
|
||||
'/^datasrc/i',
|
||||
'/^data.*/i'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Yeah-yeah, so this looks horrible. Check out htmlfilter.inc for
|
||||
* some idea of what's going on here. :)
|
||||
*/
|
||||
|
||||
$bad_attvals = Array(
|
||||
'/.*/' =>
|
||||
Array(
|
||||
'/.*/' =>
|
||||
Array(
|
||||
Array(
|
||||
'/^([\'\"])\s*\S+\s*script\s*:*(.*)([\'\"])/i',
|
||||
'/^([\'\"])\s*https*\s*:(.*)([\'\"])/i',
|
||||
'/^([\'\"])\s*mocha\s*:*(.*)([\'\"])/i',
|
||||
'/^([\'\"])\s*about\s*:(.*)([\'\"])/i'
|
||||
),
|
||||
Array(
|
||||
'\\1oddjob:\\2\\3',
|
||||
'\\1uucp:\\2\\3',
|
||||
'\\1amaretto:\\2\\3',
|
||||
'\\1round:\\2\\3'
|
||||
)
|
||||
),
|
||||
|
||||
'/^style/i' =>
|
||||
Array(
|
||||
Array(
|
||||
'/expression/i',
|
||||
'/behaviou*r/i',
|
||||
'/binding/i',
|
||||
'/url\(([\'\"]*)\s*https*:.*([\'\"]*)\)/i',
|
||||
'/url\(([\'\"]*)\s*\S+script:.*([\'\"]*)\)/i'
|
||||
),
|
||||
Array(
|
||||
'idiocy',
|
||||
'idiocy',
|
||||
'idiocy',
|
||||
'url(\\1http://securityfocus.com/\\2)',
|
||||
'url(\\1http://securityfocus.com/\\2)'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$add_attr_to_tag = Array(
|
||||
'/^a$/i' => Array('target' => '"_new"')
|
||||
);
|
||||
|
||||
function sanitize_html($body) {
|
||||
global $tag_list;
|
||||
global $rm_tags_with_content;
|
||||
global $self_closing_tags;
|
||||
global $force_tag_closing;
|
||||
global $rm_attnames;
|
||||
global $bad_attvals;
|
||||
global $add_attr_to_tag;
|
||||
return sanitize(
|
||||
$body,
|
||||
$tag_list,
|
||||
$rm_tags_with_content,
|
||||
$self_closing_tags,
|
||||
$force_tag_closing,
|
||||
$rm_attnames,
|
||||
$bad_attvals,
|
||||
$add_attr_to_tag
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
require_once("util.inc");
|
||||
require_once("db.inc");
|
||||
require_once("sanitize_html.inc");
|
||||
|
||||
function show_team($team) {
|
||||
start_table();
|
||||
|
@ -11,7 +12,7 @@ function show_team($team) {
|
|||
row("url", $team->url);
|
||||
row("type", $team->type);
|
||||
row("name_html", $team->name_html);
|
||||
row("description", $team->description);
|
||||
row("description", sanitize_html($team->description));
|
||||
}
|
||||
|
||||
function display_team_page($team) {
|
||||
|
@ -36,7 +37,7 @@ function display_team_page($team) {
|
|||
echo "<b>Team Info:</b></font></td></tr></table>";
|
||||
echo "<table>";
|
||||
if (strlen($team->description)) {
|
||||
row("<b>Description: </b>", $team->description);
|
||||
row("<b>Description: </b>", sanitize_html($team->description));
|
||||
}
|
||||
if (strlen($team->url)) {;
|
||||
row("<b>Web site: </b>", "<a href=http://$team->url>http://$team->url</a>");
|
||||
|
|
|
@ -18,39 +18,38 @@
|
|||
require_founder_login($user, $team);
|
||||
|
||||
$team_url = ereg_replace("\"", "'", $HTTP_POST_VARS["url"]);
|
||||
$pos = strpos($team_url, "http://");
|
||||
if (!($pos === false)) { // note: three equal signs
|
||||
$team_url = substr($team_url, 7);
|
||||
$x = strstr($team_url, "http://");
|
||||
if ($x) {
|
||||
$team_url = substr($team_url, 7);
|
||||
}
|
||||
$team_name = ereg_replace("\"", "'", $HTTP_POST_VARS["name"]);
|
||||
$team_name_html = ereg_replace("\"", "'", $HTTP_POST_VARS["name_html"]);
|
||||
$team_description = ereg_replace("\"", "'", $HTTP_POST_VARS["description"]);
|
||||
|
||||
|
||||
$query_team_table = sprintf(
|
||||
"update team set name = '%s',
|
||||
name_html = '%s',
|
||||
url = '%s',
|
||||
description = '%s',
|
||||
type = %d
|
||||
where id = %d",
|
||||
$team_name,
|
||||
$team_name_html,
|
||||
$team_url,
|
||||
$team_description,
|
||||
$HTTP_POST_VARS["type"],
|
||||
$team->id
|
||||
);
|
||||
$result_team_table = mysql_query($query_team_table);
|
||||
if ($result_team_table) {
|
||||
page_head("Changes accepted");
|
||||
$team_name = $team->name;
|
||||
echo "<h2>Changes Accepted</h2>";
|
||||
echo "The changes to <a href=team_display.php?id=$team->id>$team_name</a> were accepted and should now be in effect.";
|
||||
} else {
|
||||
page_head("Error");
|
||||
echo "Couldn't edit team - please try later.\n";
|
||||
}
|
||||
$query_team_table = sprintf(
|
||||
"update team set name = '%s',
|
||||
name_html = '%s',
|
||||
url = '%s',
|
||||
description = '%s',
|
||||
type = %d
|
||||
where id = %d",
|
||||
$team_name,
|
||||
$team_name_html,
|
||||
$team_url,
|
||||
$team_description,
|
||||
$HTTP_POST_VARS["type"],
|
||||
$team->id
|
||||
);
|
||||
$result_team_table = mysql_query($query_team_table);
|
||||
if ($result_team_table) {
|
||||
page_head("Changes accepted");
|
||||
$team_name = $team->name;
|
||||
echo "<h2>Changes Accepted</h2>";
|
||||
echo "The changes to <a href=team_display.php?id=$team->id>$team_name</a> were accepted and should now be in effect.";
|
||||
} else {
|
||||
page_head("Error");
|
||||
echo "Couldn't edit team - please try later.\n";
|
||||
}
|
||||
|
||||
page_tail();
|
||||
|
||||
|
|
|
@ -206,7 +206,9 @@ function no_cache() {
|
|||
// (Used during account creation and email address changes)
|
||||
|
||||
// a valid email address is of the form A@B.C
|
||||
// where A, B, C are nonempty and don't contain @ or .
|
||||
// where A, B, C are nonempty,
|
||||
// A and B don't contain @ or .,
|
||||
// and C doesn't contain @
|
||||
//
|
||||
function is_valid_email_addr($addr) {
|
||||
$x = strstr($addr, "@");
|
||||
|
@ -218,9 +220,6 @@ function is_valid_email_addr($addr) {
|
|||
if (!$y) return false;
|
||||
if (strlen($y) == strlen($x)) return false;
|
||||
if (strlen($y) == 1) return false;
|
||||
$y = substr($y, 1);
|
||||
if (strstr($y, ".")) return false;
|
||||
if (strlen($y) == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -241,4 +240,8 @@ function split_munged_email_addr($addr, $string, &$email) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// remove all HTML tags except vanilla formatting
|
||||
//
|
||||
function cleanse_html($text) {
|
||||
}
|
||||
?>
|
||||
|
|
Loading…
Reference in New Issue