Как я получаю Крон как планировщик в Python? [закрытый]

Используйте подготовленные операторы и параметризованные запросы. Это операторы SQL, которые отправляются и анализируются сервером базы данных отдельно от любых параметров. Таким образом, злоумышленник не может внедрить вредоносный SQL.

У вас в основном есть два варианта:

  1. Использование PDO (для любой поддерживаемый драйвер базы данных):
    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    
    $stmt->execute(array('name' => $name));
    
    foreach ($stmt as $row) {
        // do something with $row
    }
    
  2. Использование MySQLi (для MySQL):
    $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';
}

311
задан Damjan Pavlica 15 November 2017 в 01:41
поделиться

9 ответов

На всякий случай, если Вы используете окна, там существует pycron. Выезд http://sourceforge.net/projects/pycron/ . Для Linux я пойду или кроном или sched.

1
ответ дан JV. 29 August 2019 в 11:19
поделиться

TurboGears поставлется с возможностью запланированной задачи на основе Kronos

, я никогда не использовал Kronos непосредственно, но планирование в TG имеет достойный набор функций и серьезно.

9
ответ дан James Brady 29 August 2019 в 11:19
поделиться

Обратите внимание на Celery , у них есть периодические задачи, такие как cron.

28
ответ дан 29 August 2019 в 11:19
поделиться

Я не знаю, существует ли что-то как этот уже. Было бы легко записать Ваше собственное со временем, датой и временем и/или календарными модулями, видеть http://docs.python.org/library/time.html

, единственное беспокойство о решении для Python - то, что Ваше задание должно всегда работать и возможно быть автоматически "возрожденным" после перезагрузки, чего-то, для которого Вы делаете потребность полагаться на системно-зависимые решения.

0
ответ дан Davide 23 November 2019 в 01:12
поделиться

Нет "чистого Python" способа сделать это, потому что некоторый другой процесс должен был бы запустить Python для выполнения решения. Каждая платформа будет иметь один или двадцать различных способов запустить процессы и контролировать их прогресс. На платформах Unix крон является старым стандартом. На Mac OS X существует также launchd, который комбинирует подобный крону запуск со сторожевой функциональностью, которая может поддержать Ваш процесс, если это - то, что Вы хотите. Как только Python работает, тогда можно использовать sched модуль для планирования задач.

3
ответ дан Nick 23 November 2019 в 01:12
поделиться

Одной вещью, что в моих поисках я видел, является Python sched модуль, который мог бы быть видом вещи, которую Вы ищете.

19
ответ дан Sean 23 November 2019 в 01:12
поделиться

Вы могли просто использовать нормальный синтаксис передачи параметров 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]. Если Вы предпочитаете, чтобы синтаксис крона, анализируя его не должен был быть слишком трудным как бы то ни было.

64
ответ дан Brian 23 November 2019 в 01:12
поделиться

У меня есть небольшое исправление для метода запуска класса 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()
6
ответ дан 23 November 2019 в 01:12
поделиться

Более или менее то же самое, что и выше, но одновременно с использованием 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()
10
ответ дан 23 November 2019 в 01:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: