mirror of https://github.com/MISP/MISP
Merge branch 'thumbnail' into 2.4
commit
76d14c00cb
|
@ -36,7 +36,7 @@ sudo mysql_secure_installation
|
||||||
|
|
||||||
|
|
||||||
# Install PHP and dependencies
|
# Install PHP and dependencies
|
||||||
sudo apt-get install libapache2-mod-php php php-cli php-crypt-gpg php-dev php-json php-mysql php-opcache php-readline php-redis php-xml
|
sudo apt-get install libapache2-mod-php php php-cli php-crypt-gpg php-dev php-json php-mysql php-opcache php-readline php-redis php-xml php-gd
|
||||||
|
|
||||||
# Apply all changes
|
# Apply all changes
|
||||||
sudo systemctl restart apache2
|
sudo systemctl restart apache2
|
||||||
|
|
|
@ -46,7 +46,7 @@ class AppController extends Controller
|
||||||
|
|
||||||
public $helpers = array('Utility', 'OrgImg', 'FontAwesome');
|
public $helpers = array('Utility', 'OrgImg', 'FontAwesome');
|
||||||
|
|
||||||
private $__queryVersion = '64';
|
private $__queryVersion = '65';
|
||||||
public $pyMispVersion = '2.4.103';
|
public $pyMispVersion = '2.4.103';
|
||||||
public $phpmin = '7.0';
|
public $phpmin = '7.0';
|
||||||
public $phprec = '7.2';
|
public $phprec = '7.2';
|
||||||
|
|
|
@ -1174,15 +1174,15 @@ class AttributesController extends AppController
|
||||||
if (!$this->Attribute->exists()) {
|
if (!$this->Attribute->exists()) {
|
||||||
throw new NotFoundException('Invalid attribute');
|
throw new NotFoundException('Invalid attribute');
|
||||||
}
|
}
|
||||||
|
$conditions = array('conditions' => array('Attribute.id' => $id), 'withAttachments' => true, 'flatten' => true);
|
||||||
|
$conditions['includeAllTags'] = false;
|
||||||
|
$conditions['includeAttributeUuid'] = true;
|
||||||
|
$attribute = $this->Attribute->fetchAttributes($this->Auth->user(), $conditions);
|
||||||
|
if (empty($attribute)) {
|
||||||
|
throw new MethodNotAllowedException('Invalid attribute');
|
||||||
|
}
|
||||||
|
$attribute = $attribute[0];
|
||||||
if ($this->_isRest()) {
|
if ($this->_isRest()) {
|
||||||
$conditions = array('conditions' => array('Attribute.id' => $id), 'withAttachments' => true, 'flatten' => true);
|
|
||||||
$conditions['includeAllTags'] = false;
|
|
||||||
$conditions['includeAttributeUuid'] = true;
|
|
||||||
$attribute = $this->Attribute->fetchAttributes($this->Auth->user(), $conditions);
|
|
||||||
if (empty($attribute)) {
|
|
||||||
throw new MethodNotAllowedException('Invalid attribute');
|
|
||||||
}
|
|
||||||
$attribute = $attribute[0];
|
|
||||||
if (isset($attribute['AttributeTag'])) {
|
if (isset($attribute['AttributeTag'])) {
|
||||||
foreach ($attribute['AttributeTag'] as $k => $tag) {
|
foreach ($attribute['AttributeTag'] as $k => $tag) {
|
||||||
$attribute['Attribute']['Tag'][$k] = $tag['Tag'];
|
$attribute['Attribute']['Tag'][$k] = $tag['Tag'];
|
||||||
|
@ -1193,7 +1193,94 @@ class AttributesController extends AppController
|
||||||
$this->set('Attribute', $attribute['Attribute']);
|
$this->set('Attribute', $attribute['Attribute']);
|
||||||
$this->set('_serialize', array('Attribute'));
|
$this->set('_serialize', array('Attribute'));
|
||||||
} else {
|
} else {
|
||||||
$this->redirect('/events/view/' . $this->Attribute->data['Attribute']['event_id']);
|
$this->redirect('/events/view/' . $attribute['Attribute']['event_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function viewPicture($id, $thumbnail=false, $width=200, $height=200)
|
||||||
|
{
|
||||||
|
if (Validation::uuid($id)) {
|
||||||
|
$temp = $this->Attribute->find('first', array(
|
||||||
|
'recursive' => -1,
|
||||||
|
'conditions' => array('Attribute.uuid' => $id),
|
||||||
|
'fields' => array('Attribute.id', 'Attribute.uuid')
|
||||||
|
));
|
||||||
|
if (empty($temp)) {
|
||||||
|
throw new NotFoundException(__('Invalid attribute'));
|
||||||
|
}
|
||||||
|
$id = $temp['Attribute']['id'];
|
||||||
|
} elseif (!is_numeric($id)) {
|
||||||
|
throw new NotFoundException(__('Invalid attribute id.'));
|
||||||
|
}
|
||||||
|
$this->Attribute->id = $id;
|
||||||
|
if (!$this->Attribute->exists()) {
|
||||||
|
throw new NotFoundException('Invalid attribute');
|
||||||
|
}
|
||||||
|
$conditions = array(
|
||||||
|
'conditions' => array(
|
||||||
|
'Attribute.id' => $id,
|
||||||
|
'Attribute.type' => 'attachment'
|
||||||
|
),
|
||||||
|
'withAttachments' => true,
|
||||||
|
'includeAllTags' => false,
|
||||||
|
'includeAttributeUuid' => true,
|
||||||
|
'flatten' => true
|
||||||
|
);
|
||||||
|
$attribute = $this->Attribute->fetchAttributes($this->Auth->user(), $conditions);
|
||||||
|
if (empty($attribute)) {
|
||||||
|
throw new MethodNotAllowedException('Invalid attribute');
|
||||||
|
}
|
||||||
|
$attribute = $attribute[0];
|
||||||
|
|
||||||
|
if ($this->_isRest()) {
|
||||||
|
return $this->RestResponse->viewData($attribute['Attribute']['data'], $this->response->type());
|
||||||
|
} else {
|
||||||
|
$extension = explode('.', $attribute['Attribute']['value']);
|
||||||
|
$extension = end($extension);
|
||||||
|
if (extension_loaded('gd')) {
|
||||||
|
$image = ImageCreateFromString(base64_decode($attribute['Attribute']['data']));
|
||||||
|
if (!$thumbnail) {
|
||||||
|
ob_start ();
|
||||||
|
switch ($extension) {
|
||||||
|
case 'gif':
|
||||||
|
imagegif($image);
|
||||||
|
break;
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg':
|
||||||
|
imagejpeg($image);
|
||||||
|
break;
|
||||||
|
case 'png':
|
||||||
|
imagepng($image);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$image_data = $extension != 'gif' ? ob_get_contents() : base64_decode($attribute['Attribute']['data']);
|
||||||
|
ob_end_clean ();
|
||||||
|
imagedestroy($image);
|
||||||
|
} else { // thumbnail requested, resample picture with desired dimension
|
||||||
|
$width = isset($this->request->params['named']['width']) ? $this->request->params['named']['width'] : 150;
|
||||||
|
$height = isset($this->request->params['named']['height']) ? $this->request->params['named']['height'] : 150;
|
||||||
|
if ($extension == 'gif') {
|
||||||
|
$image_data = base64_decode($attribute['Attribute']['data']);
|
||||||
|
} else {
|
||||||
|
$extension = 'jpg';
|
||||||
|
$imageTC = ImageCreateTrueColor($width, $height);
|
||||||
|
ImageCopyResampled($imageTC, $image, 0, 0, 0, 0, $width, $height, ImageSX($image), ImageSY($image));
|
||||||
|
ob_start ();
|
||||||
|
imagejpeg ($imageTC);
|
||||||
|
$image_data = ob_get_contents();
|
||||||
|
ob_end_clean ();
|
||||||
|
imagedestroy($image);
|
||||||
|
imagedestroy($imageTC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$image_data = base64_decode($attribute['Attribute']['data']);
|
||||||
|
}
|
||||||
|
$this->response->type(strtolower(h($extension)));
|
||||||
|
$this->response->body($image_data);
|
||||||
|
$this->autoRender = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ class ACLComponent extends Component
|
||||||
'toggleToIDS' => array('perm_add'),
|
'toggleToIDS' => array('perm_add'),
|
||||||
'updateAttributeValues' => array('perm_add'),
|
'updateAttributeValues' => array('perm_add'),
|
||||||
'view' => array('*'),
|
'view' => array('*'),
|
||||||
|
'viewPicture' => array('*'),
|
||||||
),
|
),
|
||||||
'eventBlacklists' => array(
|
'eventBlacklists' => array(
|
||||||
'add' => array(),
|
'add' => array(),
|
||||||
|
|
|
@ -4811,10 +4811,15 @@ class Event extends AppModel
|
||||||
if (!empty($object['data'])) {
|
if (!empty($object['data'])) {
|
||||||
$object['image'] = $object['data'];
|
$object['image'] = $object['data'];
|
||||||
} else {
|
} else {
|
||||||
if ($object['objectType'] === 'proposal') {
|
if (extension_loaded('gd')) {
|
||||||
$object['image'] = $this->ShadowAttribute->base64EncodeAttachment($object);
|
// if extention is loaded, the data is not passed to the view because it is asynchronously fetched
|
||||||
|
$object['image'] = true; // tell the view that it is an image despite not having the actual data
|
||||||
} else {
|
} else {
|
||||||
$object['image'] = $this->Attribute->base64EncodeAttachment($object);
|
if ($object['objectType'] === 'proposal') {
|
||||||
|
$object['image'] = $this->ShadowAttribute->base64EncodeAttachment($object);
|
||||||
|
} else {
|
||||||
|
$object['image'] = $this->Attribute->base64EncodeAttachment($object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4521,7 +4521,7 @@ class Server extends AppModel
|
||||||
public function extensionDiagnostics()
|
public function extensionDiagnostics()
|
||||||
{
|
{
|
||||||
$results = array();
|
$results = array();
|
||||||
$extensions = array('redis');
|
$extensions = array('redis', 'gd');
|
||||||
foreach ($extensions as $extension) {
|
foreach ($extensions as $extension) {
|
||||||
$results['web']['extensions'][$extension] = extension_loaded($extension);
|
$results['web']['extensions'][$extension] = extension_loaded($extension);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,16 @@
|
||||||
$sigDisplay = $object['value'];
|
$sigDisplay = $object['value'];
|
||||||
if ('attachment' == $object['type'] || 'malware-sample' == $object['type'] ) {
|
if ('attachment' == $object['type'] || 'malware-sample' == $object['type'] ) {
|
||||||
if ($object['type'] == 'attachment' && isset($object['image'])) {
|
if ($object['type'] == 'attachment' && isset($object['image'])) {
|
||||||
$extension = explode('.', $object['value']);
|
if (extension_loaded('gd')) {
|
||||||
$extension = end($extension);
|
$img = '<it class="fa fa-spin fa-spinner" style="font-size: large; left: 50%; top: 50%;"></it>';
|
||||||
$uri = 'data:image/' . strtolower(h($extension)) . ';base64,' . h($object['image']);
|
$img .= '<img class="screenshot screenshot-collapsed useCursorPointer img-rounded hidden" src="' . $baseurl . '/attributes/viewPicture/' . h($object['id']) . '/1' . '" title="' . h($object['value']) . '" onload="$(this).show(200); $(this).parent().find(\'.fa-spinner\').remove();"/>';
|
||||||
echo '<img class="screenshot screenshot-collapsed useCursorPointer" src="' . $uri . '" title="' . h($object['value']) . '" />';
|
echo $img;
|
||||||
|
} else {
|
||||||
|
$extension = explode('.', $object['value']);
|
||||||
|
$extension = end($extension);
|
||||||
|
$uri = 'data:image/' . strtolower(h($extension)) . ';base64,' . h($object['image']);
|
||||||
|
echo '<img class="screenshot screenshot-collapsed useCursorPointer" src="' . $uri . '" title="' . h($object['value']) . '" />';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$filenameHash = explode('|', h($object['value']));
|
$filenameHash = explode('|', h($object['value']));
|
||||||
if (strrpos($filenameHash[0], '\\')) {
|
if (strrpos($filenameHash[0], '\\')) {
|
||||||
|
|
|
@ -170,7 +170,7 @@
|
||||||
if (isset($extensions[$context]['extensions'])):
|
if (isset($extensions[$context]['extensions'])):
|
||||||
foreach ($extensions[$context]['extensions'] as $extension => $status):
|
foreach ($extensions[$context]['extensions'] as $extension => $status):
|
||||||
?>
|
?>
|
||||||
<?php echo h($extension); ?>:… <span style="color:<?php echo $status ? 'green' : 'red';?>;font-weight:bold;"><?php echo $status ? __('OK') : __('Not loaded'); ?></span>
|
<?php echo h($extension); ?>:… <span style="color:<?php echo $status ? 'green' : 'red';?>;font-weight:bold;"><?php echo $status ? __('OK') : __('Not loaded'); ?></span><br />
|
||||||
<?php
|
<?php
|
||||||
endforeach;
|
endforeach;
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
$extensions = array('redis');
|
$extensions = array('redis', 'gd');
|
||||||
$results = array();
|
$results = array();
|
||||||
$results['phpversion'] = phpversion();
|
$results['phpversion'] = phpversion();
|
||||||
foreach ($extensions as $extension) {
|
foreach ($extensions as $extension) {
|
||||||
|
|
|
@ -848,12 +848,18 @@ a.proposal_link_red:hover {
|
||||||
|
|
||||||
.screenshot_box {
|
.screenshot_box {
|
||||||
display:none;
|
display:none;
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top:150px;
|
top: 100px;
|
||||||
background-color:#f4f4f4;
|
left: 20px;
|
||||||
border-radius: 11px 11px 10px 10px;
|
right: 20px;
|
||||||
box-shadow: 4px 4px 4px #333;
|
|
||||||
z-index:5;
|
z-index:5;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.screenshot_box-content {
|
||||||
|
margin: auto;
|
||||||
|
display: block;
|
||||||
|
background-color:#f4f4f4;
|
||||||
|
box-shadow: 4px 4px 4px #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ajax_popover_form legend, .ajax_popover_form .legend {
|
.ajax_popover_form legend, .ajax_popover_form .legend {
|
||||||
|
|
|
@ -79,13 +79,22 @@ function genericPopup(url, popupTarget, callback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function screenshotPopup(screenshotData, title) {
|
function screenshotPopup(url, title) {
|
||||||
popupHtml = '<img src="' + screenshotData + '" id="screenshot-image" title="' + title + '" />';
|
if (!url.startsWith('data:image/')) {
|
||||||
|
url = url.slice(0, -1);
|
||||||
|
}
|
||||||
|
popupHtml = '<it class="fa fa-spin fa-spinner" style="font-size: xx-large; color: white; position: fixed; left: 50%; top: 50%;"></it>'
|
||||||
|
popupHtml += '<img class="screenshot_box-content hidden" src="' + url + '" id="screenshot-image" title="' + title + '" alt="' + title + '" onload="$(this).show(); $(this).parent().find(\'.fa-spinner\').remove();"/>';
|
||||||
popupHtml += '<div class="close-icon useCursorPointer" onClick="closeScreenshot();"></div>';
|
popupHtml += '<div class="close-icon useCursorPointer" onClick="closeScreenshot();"></div>';
|
||||||
|
if (!url.startsWith('data:image/')) {
|
||||||
|
popupHtml += '<a class="close-icon useCursorPointer fa fa-expand" style="right: 20px; background: black; color: white; text-decoration: none;" target="_blank" href="' + url + '" ></a>';
|
||||||
|
}
|
||||||
|
popupHtml += '<div style="height: 20px;"></div>'; // see bottom of image for large one
|
||||||
$('#screenshot_box').html(popupHtml);
|
$('#screenshot_box').html(popupHtml);
|
||||||
$('#screenshot_box').show();
|
$('#screenshot_box').css({
|
||||||
left = ($(window).width() / 2) - ($('#screenshot-image').width() / 2);
|
display: 'block',
|
||||||
$('#screenshot_box').css({'left': left + 'px'});
|
top: (document.documentElement.scrollTop + 100) + 'px'
|
||||||
|
});
|
||||||
$("#gray_out").fadeIn();
|
$("#gray_out").fadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,8 @@ installDepsPhp72 () {
|
||||||
php-dev \
|
php-dev \
|
||||||
php-json php-xml php-mysql php-opcache php-readline php-mbstring \
|
php-json php-xml php-mysql php-opcache php-readline php-mbstring \
|
||||||
php-pear \
|
php-pear \
|
||||||
php-redis php-gnupg
|
php-redis php-gnupg \
|
||||||
|
php-gd
|
||||||
|
|
||||||
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
|
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
|
||||||
do
|
do
|
||||||
|
|
|
@ -103,7 +103,7 @@ sudo a2dissite 000-default
|
||||||
sudo a2ensite default-ssl
|
sudo a2ensite default-ssl
|
||||||
|
|
||||||
# Install PHP and dependencies
|
# Install PHP and dependencies
|
||||||
sudo apt-get install libapache2-mod-php php php-cli php-gnupg php-dev php-json php-mysql php-opcache php-readline php-redis php-xml php-mbstring -y
|
sudo apt-get install libapache2-mod-php php php-cli php-gnupg php-dev php-json php-mysql php-opcache php-readline php-redis php-xml php-mbstring php-gd -y
|
||||||
|
|
||||||
# Apply all changes
|
# Apply all changes
|
||||||
sudo systemctl restart apache2
|
sudo systemctl restart apache2
|
||||||
|
|
|
@ -420,7 +420,8 @@ installDepsPhp70 () {
|
||||||
php-dev \
|
php-dev \
|
||||||
php-json php-xml php-mysql php-opcache php-readline php-mbstring \
|
php-json php-xml php-mysql php-opcache php-readline php-mbstring \
|
||||||
php-pear \
|
php-pear \
|
||||||
php-redis php-gnupg
|
php-redis php-gnupg \
|
||||||
|
php-gd
|
||||||
|
|
||||||
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
|
for key in upload_max_filesize post_max_size max_execution_time max_input_time memory_limit
|
||||||
do
|
do
|
||||||
|
@ -443,7 +444,8 @@ installDepsPhp73 () {
|
||||||
php7.3-dev \
|
php7.3-dev \
|
||||||
php7.3-json php7.3-xml php7.3-mysql php7.3-opcache php7.3-readline php7.3-mbstring \
|
php7.3-json php7.3-xml php7.3-mysql php7.3-opcache php7.3-readline php7.3-mbstring \
|
||||||
php-pear \
|
php-pear \
|
||||||
php-redis php-gnupg
|
php-redis php-gnupg \
|
||||||
|
php-gd
|
||||||
}
|
}
|
||||||
# <snippet-end 0_installDepsPhp73.sh>
|
# <snippet-end 0_installDepsPhp73.sh>
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,7 @@ doas pkg_add -v fcgi-cgi fcgi
|
||||||
If on OpenBSD 6.3, upgrade to 6.4 to make your life much easier.
|
If on OpenBSD 6.3, upgrade to 6.4 to make your life much easier.
|
||||||
|
|
||||||
```
|
```
|
||||||
doas pkg_add -v php-mysqli php-pcntl php-pdo_mysql php-apache pecl72-redis
|
doas pkg_add -v php-mysqli php-pcntl php-pdo_mysql php-apache pecl72-redis php-gd
|
||||||
```
|
```
|
||||||
|
|
||||||
#### /etc/php-7.2.ini
|
#### /etc/php-7.2.ini
|
||||||
|
|
|
@ -68,7 +68,7 @@ sudo yum install gcc git zip \
|
||||||
libxslt-devel zlib-devel ssdeep-devel -y
|
libxslt-devel zlib-devel ssdeep-devel -y
|
||||||
|
|
||||||
# Install PHP 7.1 from SCL, see https://www.softwarecollections.org/en/scls/rhscl/rh-php71/
|
# Install PHP 7.1 from SCL, see https://www.softwarecollections.org/en/scls/rhscl/rh-php71/
|
||||||
sudo yum install rh-php71 rh-php71-php-fpm rh-php71-php-devel rh-php71-php-mysqlnd rh-php71-php-mbstring rh-php71-php-xml rh-php71-php-bcmath rh-php71-php-opcache -y
|
sudo yum install rh-php71 rh-php71-php-fpm rh-php71-php-devel rh-php71-php-mysqlnd rh-php71-php-mbstring rh-php71-php-xml rh-php71-php-bcmath rh-php71-php-opcache rh-php71-php-gd -y
|
||||||
|
|
||||||
# Install Python 3.6 from SCL, see
|
# Install Python 3.6 from SCL, see
|
||||||
# https://www.softwarecollections.org/en/scls/rhscl/rh-python36/
|
# https://www.softwarecollections.org/en/scls/rhscl/rh-python36/
|
||||||
|
|
|
@ -77,7 +77,7 @@ libxml2-dev libxslt1-dev zlib1g-dev
|
||||||
|
|
||||||
#sudo /etc/init.d/redis-server restart
|
#sudo /etc/init.d/redis-server restart
|
||||||
|
|
||||||
sudo apt install -y libapache2-mod-php7.0 php7.0 php7.0-cli php7.0-mbstring php7.0-dev php7.0-json php7.0-xml php7.0-mysql php7.0-opcache php7.0-readline php-redis php-gnupg
|
sudo apt install -y libapache2-mod-php7.0 php7.0 php7.0-cli php7.0-mbstring php7.0-dev php7.0-json php7.0-xml php7.0-mysql php7.0-opcache php7.0-readline php-redis php-gnupg php-gd
|
||||||
|
|
||||||
sudo apt install -y \
|
sudo apt install -y \
|
||||||
mariadb-client \
|
mariadb-client \
|
||||||
|
|
|
@ -61,7 +61,7 @@ python3-setuptools python3-dev python3-pip python3-redis python3-zmq virtualenv
|
||||||
mariadb-client \
|
mariadb-client \
|
||||||
mariadb-server \
|
mariadb-server \
|
||||||
apache2 apache2-doc apache2-utils \
|
apache2 apache2-doc apache2-utils \
|
||||||
libapache2-mod-php7.3 php7.3 php7.3-cli php7.3-mbstring php7.3-dev php7.3-json php7.3-xml php7.3-mysql php7.3-opcache php7.3-readline php-redis php-gnupg \
|
libapache2-mod-php7.3 php7.3 php7.3-cli php7.3-mbstring php7.3-dev php7.3-json php7.3-xml php7.3-mysql php7.3-opcache php7.3-readline php-redis php-gnupg php-gd \
|
||||||
libpq5 libjpeg-dev libfuzzy-dev ruby asciidoctor \
|
libpq5 libjpeg-dev libfuzzy-dev ruby asciidoctor \
|
||||||
jq ntp ntpdate jupyter-notebook imagemagick tesseract-ocr \
|
jq ntp ntpdate jupyter-notebook imagemagick tesseract-ocr \
|
||||||
libxml2-dev libxslt1-dev zlib1g-dev
|
libxml2-dev libxslt1-dev zlib1g-dev
|
||||||
|
|
|
@ -141,7 +141,7 @@ Also make sure the variable ${VIRT_USER} is set to the user you created when you
|
||||||
|
|
||||||
#### Install PHP and dependencies
|
#### Install PHP and dependencies
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install libapache2-mod-php php php-cli php-gnupg php-dev php-json php-mysql php-opcache php-readline php-redis php-xml php-mbstring -y
|
sudo apt-get install libapache2-mod-php php php-cli php-gnupg php-dev php-json php-mysql php-opcache php-readline php-redis php-xml php-mbstring php-gd -y
|
||||||
```
|
```
|
||||||
|
|
||||||
# Apply all changes
|
# Apply all changes
|
||||||
|
|
Loading…
Reference in New Issue