security: faza 2 - safeUnlink() i escaping XSS w szablonach artykulow
- ProductRepository: dodano safeUnlink() z walidacja realpath() - zapobiega path traversal - ArticleRepository: to samo, 4 metody usuwania plikow zaktualizowane - templates/articles/article-full.php: htmlspecialchars() na tytule, SERVER_NAME i $url - templates/articles/article-entry.php: htmlspecialchars() na tytule i $url (3 miejsca) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -318,9 +318,7 @@ class ArticleRepository
|
||||
|
||||
if (is_array($results)) {
|
||||
foreach ($results as $row) {
|
||||
if (file_exists('../' . $row['src'])) {
|
||||
unlink('../' . $row['src']);
|
||||
}
|
||||
$this->safeUnlink($row['src']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,9 +335,7 @@ class ArticleRepository
|
||||
|
||||
if (is_array($results)) {
|
||||
foreach ($results as $row) {
|
||||
if (file_exists('../' . $row['src'])) {
|
||||
unlink('../' . $row['src']);
|
||||
}
|
||||
$this->safeUnlink($row['src']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,9 +815,7 @@ class ArticleRepository
|
||||
$results = $this->db->select('pp_articles_files', '*', ['article_id' => null]);
|
||||
if (is_array($results)) {
|
||||
foreach ($results as $row) {
|
||||
if (file_exists('../' . $row['src'])) {
|
||||
unlink('../' . $row['src']);
|
||||
}
|
||||
$this->safeUnlink($row['src']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,15 +830,29 @@ class ArticleRepository
|
||||
$results = $this->db->select('pp_articles_images', '*', ['article_id' => null]);
|
||||
if (is_array($results)) {
|
||||
foreach ($results as $row) {
|
||||
if (file_exists('../' . $row['src'])) {
|
||||
unlink('../' . $row['src']);
|
||||
}
|
||||
$this->safeUnlink($row['src']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->delete('pp_articles_images', ['article_id' => null]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Usuwa plik z dysku tylko jeśli ścieżka pozostaje wewnątrz katalogu upload/.
|
||||
* Zapobiega path traversal przy danych z bazy.
|
||||
*/
|
||||
private function safeUnlink(string $src): void
|
||||
{
|
||||
$base = realpath('../upload');
|
||||
if (!$base) {
|
||||
return;
|
||||
}
|
||||
$full = realpath('../' . ltrim($src, '/'));
|
||||
if ($full && strpos($full, $base . DIRECTORY_SEPARATOR) === 0 && is_file($full)) {
|
||||
unlink($full);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pobiera artykuly opublikowane w podanym zakresie dat.
|
||||
*/
|
||||
|
||||
@@ -1601,9 +1601,7 @@ class ProductRepository
|
||||
$results = $this->db->select( 'pp_shop_products_files', '*', [ 'AND' => [ 'product_id' => $productId, 'to_delete' => 1 ] ] );
|
||||
if ( is_array( $results ) ) {
|
||||
foreach ( $results as $row ) {
|
||||
if ( file_exists( '../' . $row['src'] ) ) {
|
||||
unlink( '../' . $row['src'] );
|
||||
}
|
||||
$this->safeUnlink( $row['src'] );
|
||||
}
|
||||
}
|
||||
$this->db->delete( 'pp_shop_products_files', [ 'AND' => [ 'product_id' => $productId, 'to_delete' => 1 ] ] );
|
||||
@@ -1614,9 +1612,7 @@ class ProductRepository
|
||||
$results = $this->db->select( 'pp_shop_products_images', '*', [ 'AND' => [ 'product_id' => $productId, 'to_delete' => 1 ] ] );
|
||||
if ( is_array( $results ) ) {
|
||||
foreach ( $results as $row ) {
|
||||
if ( file_exists( '../' . $row['src'] ) ) {
|
||||
unlink( '../' . $row['src'] );
|
||||
}
|
||||
$this->safeUnlink( $row['src'] );
|
||||
}
|
||||
}
|
||||
$this->db->delete( 'pp_shop_products_images', [ 'AND' => [ 'product_id' => $productId, 'to_delete' => 1 ] ] );
|
||||
@@ -2125,14 +2121,28 @@ class ProductRepository
|
||||
$results = $this->db->select( 'pp_shop_products_images', '*', [ 'product_id' => null ] );
|
||||
if ( is_array( $results ) ) {
|
||||
foreach ( $results as $row ) {
|
||||
if ( file_exists( '../' . $row['src'] ) ) {
|
||||
unlink( '../' . $row['src'] );
|
||||
}
|
||||
$this->safeUnlink( $row['src'] );
|
||||
}
|
||||
}
|
||||
$this->db->delete( 'pp_shop_products_images', [ 'product_id' => null ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Usuwa plik z dysku tylko jeśli ścieżka pozostaje wewnątrz katalogu upload/.
|
||||
* Zapobiega path traversal przy danych z bazy.
|
||||
*/
|
||||
private function safeUnlink(string $src): void
|
||||
{
|
||||
$base = realpath('../upload');
|
||||
if (!$base) {
|
||||
return;
|
||||
}
|
||||
$full = realpath('../' . ltrim($src, '/'));
|
||||
if ($full && strpos($full, $base . DIRECTORY_SEPARATOR) === 0 && is_file($full)) {
|
||||
unlink($full);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Oznacza plik do usunięcia.
|
||||
*/
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
<div class="col-12 col-md-6 ">
|
||||
<div class="article-entry">
|
||||
<? $this -> article['language']['seo_link'] ? $url = $this -> article['language']['seo_link'] : $url = 'a-' . $this -> article['id'] . '-' . \Shared\Helpers\Helpers::seo( $this -> article['language']['title'] );?>
|
||||
<? $safeTitle = htmlspecialchars( $this -> article['language']['title'], ENT_QUOTES, 'UTF-8' ); $safeUrl = htmlspecialchars( $url, ENT_QUOTES, 'UTF-8' );?>
|
||||
<div class="blog-image">
|
||||
<a href="/<?= $url;?>" title="<?= $this -> article['language']['title'];?>" <? if ( $this -> article['language']['noindex'] ):?>rel="nofollow"<? endif;?>> <img src="<?= \front\Views\Articles::getImage( $this -> article );?>" alt="<?= $this -> article['language']['title'];?>"></a>
|
||||
<a href="/<?= $safeUrl;?>" title="<?= $safeTitle;?>" <? if ( $this -> article['language']['noindex'] ):?>rel="nofollow"<? endif;?>> <img src="<?= \front\Views\Articles::getImage( $this -> article );?>" alt="<?= $safeTitle;?>"></a>
|
||||
</div>
|
||||
<h3 class="article-title">
|
||||
<a href="/<? if ( \Shared\Helpers\Helpers::get_session( 'current-lang' ) != ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->defaultLanguage() ) echo \Shared\Helpers\Helpers::get_session( 'current-lang' ) . '/';?><?= $url;?>" title="<?= $this -> article['language']['title'];?>" <? if ( $this -> article['language']['noindex'] ):?>rel="nofollow"<? endif;?>><?= $this -> article['language']['title'];?></a>
|
||||
<a href="/<? if ( \Shared\Helpers\Helpers::get_session( 'current-lang' ) != ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->defaultLanguage() ) echo \Shared\Helpers\Helpers::get_session( 'current-lang' ) . '/';?><?= $safeUrl;?>" title="<?= $safeTitle;?>" <? if ( $this -> article['language']['noindex'] ):?>rel="nofollow"<? endif;?>><?= $safeTitle;?></a>
|
||||
</h3>
|
||||
<div class="date-add"><?= date( 'd.m.Y', strtotime( $this -> article['date_add'] ) );?></div>
|
||||
<div class="entry">
|
||||
@@ -32,6 +33,6 @@
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<a href="/<?= $url;?>" class="btn btn-success" title="<?= $this -> article['language']['title'];?>" <? if ( $this -> article['language']['noindex'] ):?>rel="nofollow"<? endif;?>><span class="text"><?= $lang['wiecej'];?></span></a>
|
||||
<a href="/<?= $safeUrl;?>" class="btn btn-success" title="<?= $safeTitle;?>" <? if ( $this -> article['language']['noindex'] ):?>rel="nofollow"<? endif;?>><span class="text"><?= $lang['wiecej'];?></span></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -8,24 +8,26 @@ $text = \front\Views\Articles::generateHeadersIds( $text );
|
||||
$this -> article['language']['seo_link'] ? $url = $this -> article['language']['seo_link'] : $url = 'a-' . $this -> article['id'] . '-' . \Shared\Helpers\Helpers::seo( $this -> article['language']['title'] );
|
||||
|
||||
if ( $this -> article['show_title'] )
|
||||
echo '<h3 class="article-title">' . $this -> article['language']['title'] . '</h3>';
|
||||
echo '<h3 class="article-title">' . htmlspecialchars( $this -> article['language']['title'], ENT_QUOTES, 'UTF-8' ) . '</h3>';
|
||||
|
||||
if ( $this -> article['social_icons'] ):
|
||||
$safeHost = htmlspecialchars( $_SERVER['SERVER_NAME'], ENT_QUOTES, 'UTF-8' );
|
||||
$safeUrl = htmlspecialchars( $url, ENT_QUOTES, 'UTF-8' );
|
||||
?>
|
||||
<div class="social-icons">
|
||||
<a class="fb" href="http://www.facebook.com/sharer.php?u=http://www.<?= $_SERVER['SERVER_NAME'];?>/<?= $url;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;" title="facebook" target="_blank" rel="nofollow">
|
||||
<a class="fb" href="http://www.facebook.com/sharer.php?u=http://www.<?= $safeHost;?>/<?= $safeUrl;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;" title="facebook" target="_blank" rel="nofollow">
|
||||
<img src="/images/system/logo-facebook.jpg" alt="facebook">
|
||||
</a>
|
||||
<a class="pinterest" href="http://pinterest.com/pin/create/button/?url=http://www.<?= $_SERVER['SERVER_NAME'];?>/<?= $url;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;" title="pinterest" target="_blank" rel="nofollow">
|
||||
<a class="pinterest" href="http://pinterest.com/pin/create/button/?url=http://www.<?= $safeHost;?>/<?= $safeUrl;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;" title="pinterest" target="_blank" rel="nofollow">
|
||||
<img src="/images/system/logo-pinterest.jpg" alt="pinterest">
|
||||
</a>
|
||||
<a class="twitter" href="http://twitter.com/share?url=http://www.<?= $_SERVER['SERVER_NAME'];?>/<?= $url;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=450,width=600');return false;" title="twitter" target="_blank" rel="nofollow">
|
||||
<a class="twitter" href="http://twitter.com/share?url=http://www.<?= $safeHost;?>/<?= $safeUrl;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=450,width=600');return false;" title="twitter" target="_blank" rel="nofollow">
|
||||
<img src="/images/system/logo-twitter.jpg" alt="twitter">
|
||||
</a>
|
||||
<a class="linkedin" href="http://www.linkedin.com/shareArticle?mini=true&url=http://www.<?= $_SERVER['SERVER_NAME'];?>/<?= $url;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=500,width=850');return false;" title="linked in" target="_blank" rel="nofollow">
|
||||
<a class="linkedin" href="http://www.linkedin.com/shareArticle?mini=true&url=http://www.<?= $safeHost;?>/<?= $safeUrl;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=500,width=850');return false;" title="linked in" target="_blank" rel="nofollow">
|
||||
<img src="/images/system/logo-linkedin.jpg" alt="linkedin">
|
||||
</a>
|
||||
<a class="gp" href="https://plus.google.com/share?url=http://www.<?= $_SERVER['SERVER_NAME'];?>/<?= $url;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;" title="google+" target="_blank" rel="nofollow">
|
||||
<a class="gp" href="https://plus.google.com/share?url=http://www.<?= $safeHost;?>/<?= $safeUrl;?>" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=600,width=600');return false;" title="google+" target="_blank" rel="nofollow">
|
||||
<img src="/images/system/logo-google.jpg" alt="google+">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user