Используйте подготовленные операторы и параметризованные запросы. Это операторы SQL, которые отправляются и анализируются сервером базы данных отдельно от любых параметров. Таким образом, злоумышленник не может внедрить вредоносный SQL.
У вас в основном есть два варианта:
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array('name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
Если вы подключаетесь к база данных, отличная от MySQL, есть вторая опция, зависящая от драйвера, к которой вы можете обратиться (например, pg_prepare()
и pg_execute()
для PostgreSQL). PDO является универсальной опцией.
Обратите внимание, что при использовании PDO
для доступа к базе данных MySQL real подготовленные операторы не используются по умолчанию. Чтобы исправить это, вы должны отключить эмуляцию подготовленных операторов. Пример создания соединения с использованием PDO:
$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
В приведенном выше примере режим ошибки не является строго необходимым, но рекомендуется добавить его. Таким образом, сценарий не остановится с Fatal Error
, когда что-то пойдет не так. И это дает разработчику шанс catch
получить любую ошибку (ы), которые являются throw
n как PDOException
s.
Однако обязательной является первая setAttribute()
строка, которая сообщает PDO об отключении эмулируемых подготовленных операторов и использует подготовленные операторы real . Это гарантирует, что оператор и значения не будут разбираться с PHP перед отправкой на сервер MySQL (предоставление возможности злоумышленнику возможности внедрить вредоносный SQL).
Хотя вы можете установить charset
в варианты конструктора, важно отметить, что «более старые» версии PHP (& lt; 5.3.6) молча игнорировали параметр charset в DSN.
Случается, что оператор SQL, который вы передаете prepare
, анализируется и компилируется сервером базы данных. Указав параметры (либо ?
, либо именованный параметр, такой как :name
в примере выше), вы указываете механизм базы данных, в который вы хотите включить фильтр. Затем, когда вы вызываете execute
, подготовленный оператор объединяется со значениями параметров, которые вы указываете.
Важно то, что значения параметров объединены с компилируемым оператором, а не с строкой SQL. SQL-инъекция работает, обманывая сценарий, включая вредоносные строки, когда он создает SQL для отправки в базу данных. Поэтому, отправляя фактический SQL отдельно от параметров, вы ограничиваете риск того, что закончите то, чего не намеревались. Любые параметры, которые вы отправляете при использовании подготовленного оператора, будут обрабатываться только как строки (хотя механизм базы данных может сделать некоторую оптимизацию, поэтому, конечно, параметры могут также оказаться как числа). В приведенном выше примере, если переменная $name
содержит 'Sarah'; DELETE FROM employees
, результатом будет просто поиск строки "'Sarah'; DELETE FROM employees"
, и вы не получите пустую таблицу .
Еще одно преимущество использования подготовленных операторов состоит в том, что если вы выполняете один и тот же оператор много раз в одном сеансе, он будет анализироваться и компилироваться один раз, давая вам некоторую прибыль от скорости.
О, и поскольку вы спросили, как это сделать для вставки, вот пример (с использованием PDO):
$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');
$preparedStatement->execute(array('column' => $unsafeValue));
Пока вы все еще можете использовать подготовленные операторы для параметров запроса, сама структура самого динамического запроса не может быть параметризована, и некоторые функции запроса не могут быть параметризованы.
Для этих конкретных сценариев лучше всего использовать фильтр белого списка, который ограничивает возможные значения.
// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
$dir = 'ASC';
}
На всякий случай, если Вы используете окна, там существует pycron. Выезд http://sourceforge.net/projects/pycron/ . Для Linux я пойду или кроном или sched.
TurboGears поставлется с возможностью запланированной задачи на основе Kronos
, я никогда не использовал Kronos непосредственно, но планирование в TG имеет достойный набор функций и серьезно.
Обратите внимание на Celery , у них есть периодические задачи, такие как cron.
Я не знаю, существует ли что-то как этот уже. Было бы легко записать Ваше собственное со временем, датой и временем и/или календарными модулями, видеть http://docs.python.org/library/time.html
, единственное беспокойство о решении для Python - то, что Ваше задание должно всегда работать и возможно быть автоматически "возрожденным" после перезагрузки, чего-то, для которого Вы делаете потребность полагаться на системно-зависимые решения.
Нет "чистого Python" способа сделать это, потому что некоторый другой процесс должен был бы запустить Python для выполнения решения. Каждая платформа будет иметь один или двадцать различных способов запустить процессы и контролировать их прогресс. На платформах Unix крон является старым стандартом. На Mac OS X существует также launchd, который комбинирует подобный крону запуск со сторожевой функциональностью, которая может поддержать Ваш процесс, если это - то, что Вы хотите. Как только Python работает, тогда можно использовать sched модуль для планирования задач.
Одной вещью, что в моих поисках я видел, является Python sched
модуль, который мог бы быть видом вещи, которую Вы ищете.
Вы могли просто использовать нормальный синтаксис передачи параметров Python для определения crontab. Например, предположите, что мы определяем Класс событий как указано ниже:
from datetime import datetime, timedelta
import time
# Some utility classes / functions first
class AllMatch(set):
"""Universal set - match everything"""
def __contains__(self, item): return True
allMatch = AllMatch()
def conv_to_set(obj): # Allow single integer to be provided
if isinstance(obj, (int,long)):
return set([obj]) # Single item
if not isinstance(obj, set):
obj = set(obj)
return obj
# The actual Event class
class Event(object):
def __init__(self, action, min=allMatch, hour=allMatch,
day=allMatch, month=allMatch, dow=allMatch,
args=(), kwargs={}):
self.mins = conv_to_set(min)
self.hours= conv_to_set(hour)
self.days = conv_to_set(day)
self.months = conv_to_set(month)
self.dow = conv_to_set(dow)
self.action = action
self.args = args
self.kwargs = kwargs
def matchtime(self, t):
"""Return True if this event should trigger at the specified datetime"""
return ((t.minute in self.mins) and
(t.hour in self.hours) and
(t.day in self.days) and
(t.month in self.months) and
(t.weekday() in self.dow))
def check(self, t):
if self.matchtime(t):
self.action(*self.args, **self.kwargs)
(Примечание: Не полностью протестированный)
Затем Ваш CronTab может быть указан в нормальном синтаксисе Python как:
c = CronTab(
Event(perform_backup, 0, 2, dow=6 ),
Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)
Этот способ, которым Вы получаете полную мощность механики аргумента Python (смешивание позиционного и ключевое слово args, и может использовать символьные имена для имен недель и месяцев)
класс CronTab был бы определен как просто спящий в мелких инкрементах и называющий проверку () на каждом событии. (Существует, вероятно, некоторая тонкость с летним временем / часовые пояса для опасаний хотя). Вот быстрая реализация:
class CronTab(object):
def __init__(self, *events):
self.events = events
def run(self):
t=datetime(*datetime.now().timetuple()[:5])
while 1:
for e in self.events:
e.check(t)
t += timedelta(minutes=1)
while datetime.now() < t:
time.sleep((t - datetime.now()).seconds)
Несколько вещей отметить: рабочие дни Python / месяцы являются индексированным нулем (в отличие от крона), и тот диапазон исключает последний элемент, следовательно синтаксис как "1-5" становится диапазоном (0,5) - т.е. [0,1,2,3,4]. Если Вы предпочитаете, чтобы синтаксис крона, анализируя его не должен был быть слишком трудным как бы то ни было.
У меня есть небольшое исправление для метода запуска класса CronTab, предложенного Брайаном .
Отсчет времени отставал на одну секунду, что приводило к односекундной жесткой петле в конце каждой минуты.
class CronTab(object):
def __init__(self, *events):
self.events = events
def run(self):
t=datetime(*datetime.now().timetuple()[:5])
while 1:
for e in self.events:
e.check(t)
t += timedelta(minutes=1)
n = datetime.now()
while n < t:
s = (t - n).seconds + 1
time.sleep(s)
n = datetime.now()
Более или менее то же самое, что и выше, но одновременно с использованием gevent :)
"""Gevent based crontab implementation"""
from datetime import datetime, timedelta
import gevent
# Some utility classes / functions first
def conv_to_set(obj):
"""Converts to set allowing single integer to be provided"""
if isinstance(obj, (int, long)):
return set([obj]) # Single item
if not isinstance(obj, set):
obj = set(obj)
return obj
class AllMatch(set):
"""Universal set - match everything"""
def __contains__(self, item):
return True
allMatch = AllMatch()
class Event(object):
"""The Actual Event Class"""
def __init__(self, action, minute=allMatch, hour=allMatch,
day=allMatch, month=allMatch, daysofweek=allMatch,
args=(), kwargs={}):
self.mins = conv_to_set(minute)
self.hours = conv_to_set(hour)
self.days = conv_to_set(day)
self.months = conv_to_set(month)
self.daysofweek = conv_to_set(daysofweek)
self.action = action
self.args = args
self.kwargs = kwargs
def matchtime(self, t1):
"""Return True if this event should trigger at the specified datetime"""
return ((t1.minute in self.mins) and
(t1.hour in self.hours) and
(t1.day in self.days) and
(t1.month in self.months) and
(t1.weekday() in self.daysofweek))
def check(self, t):
"""Check and run action if needed"""
if self.matchtime(t):
self.action(*self.args, **self.kwargs)
class CronTab(object):
"""The crontab implementation"""
def __init__(self, *events):
self.events = events
def _check(self):
"""Check all events in separate greenlets"""
t1 = datetime(*datetime.now().timetuple()[:5])
for event in self.events:
gevent.spawn(event.check, t1)
t1 += timedelta(minutes=1)
s1 = (t1 - datetime.now()).seconds + 1
print "Checking again in %s seconds" % s1
job = gevent.spawn_later(s1, self._check)
def run(self):
"""Run the cron forever"""
self._check()
while True:
gevent.sleep(60)
import os
def test_task():
"""Just an example that sends a bell and asd to all terminals"""
os.system('echo asd | wall')
cron = CronTab(
Event(test_task, 22, 1 ),
Event(test_task, 0, range(9,18,2), daysofweek=range(0,5)),
)
cron.run()