Обчислення математичних формул на PHP та Javascript - Kosmom blog

Привіт всім. Сьогодні йтиметься про завдання обчислення заданої користувачем функції. Наприклад, ми робимо сервіс для побудови графіків з можливістю задати функцію, або робимо якийсь аналог Excel, у якому за заданими формулами необхідно провести обчислення.

Рішення ми шукатимемо найпростішими серверними та клієнтськими мовами - PHP і Javascript.

Отже – нам треба якимось чином розпарити рядок, введений користувачем. У цьому переконається, що рядок – справжня формула. Ми можемо за допомогою хитрих маніпуляцій розбити рядок на операції, функції, намагатися обчислити вкладеність, знайти зіставлення вже створених математичних функцій і знайти відповідь. Все це надто складно. Для цих мов – існує злий операторeval().

Eval- дозволяє виконати довільний рядок. Зло цієї функції полягає в тому, що користувач може в якості рядка вказати багато шкідливого коду і таким чином отримати доступ або обрушити що-небудь на сервері. Тому – якщо вирішувати завдання через eval – потрібно лише переконатися, що користувач ввів допустимий рядок.

Ми, до речі, можемо також дозволити користувачеві посилатися у формулі на допустимі змінні конкретного коду, а також власні функції користувача. Потрібно лише попередньо оголосити коло цих змінних і описати функції.

Зразкова формула може виглядати так

У формулі – ми заздалегідь кажемо користувачеві, що змінну можна використовувати лише через лапки. Це дозволить нам не допустити помилок, пов'язаних зі злиттям змінних з функціями чи діями.

Розподіл на нуль допустимий в PHP, він просто поверне 0. Інші оператори сумуватимуться окремо. наJavascript - поділ на 0 видасть нескінченність, але випадок приватний і не несе ніякого смислового навантаження, головне, щоб програма не спотикнулася, а продовжила своє виконання.

Щоб виконати перевірку – ми можемо вдатися до регулярних виразів, дізнавшись, чи формула містить лише допустимі символи, чи щось ще. Але це довго з погляду обчислень. Ми можемо піти простіше. Можемо замінити всі дозволені конструкції на пустушки і порівняти в кінці рядок із порожнечою. Якщо символи залишаються, значить помилка, введені заборонені символи. Ми також можемо перевірити кількість відкритих і закритих дужок. Можемо виконати ще низку перевірок, але для безпеки вистачить цього. Якщо щось у формулі не вдасться - буде виведено порожній результат.

Для реалізації вищенаведеного – перерахуємо всі дозволені конструкції. Тільки порядок заміни має йти від загального до приватного. Тобто спочатку – найбільш загальні вирази, наприклад«asin(», потім«sin(», потім«(» ).

Ось і всі перевірки. Залишається тільки зробити заміну нашої змінної та виконати злу операцію обчислення

++ і -- ми забороняємо тому, що вони змінюють вихідну змінну, що може бути неприпустимо. На . На початку рядка перевірку можна робити, т.к. спочатку рядок буде порожній і ми його очищатимемо якщо буде використовуватися цикл.

Можна використовувати це як завгодно, загнати в функцію, цикл. Для JavaScript все аналогічно.