Проблема с сертификатом Let’s Encrypt на старых устройствах

30 сентября 2021 года истёк срок действия корневого сертификата DST Root CA X3. В результате устаревшие устройства, которые давно не получали обновлений и не поддерживают новый корневой сертификат ISRG Root X1, перестали доверять старому сертификату и при посещении сайтов, использующих сертификаты от Let’s Encrypt, выдают предупреждения или не могут установить защищённое соединение.

Перечень устройств, считающихся устаревшими

К устаревшим устройствам относятся системы возрастом старше 5 лет, среди которых:

  • Windows XP до SP3 (а также для SP3 и Windows 7, если не производилось автоматическое обновление корневых сертификатов);
  • macOS до 10.12.1;
  • iOS до 10;
  • Android до 2.3.6 (при этом доступ к сервисам еще может быть, из-за особенностей проверки корневых сертификатов, а версии до 7.1.1 перестанут поддерживать сертификат в 2024 году);
  • Ubuntu до 16.04;
  • Debian до 8;
  • Sony PlayStation 3 и 4 с прошивками до 5.00;
  • Старые модели смарт-телевизоров и умных домашних устройств;
  • Устройства, использующие OpenSSL версии 1.0.x;
Способы решения проблемы

Решить проблему можно несколькими способами. Лучшем решением будет обновление ПО до последних версий, где уже включена поддержка нового корневого сертификата. Принимать меры по решению проблемы стоит только в том случае, если это необходимо, например, довольно крупная часть аудитории сервиса использует устаревшее ПО и они критичны для проекта. В ином случае стоит пренебречь текущей ситуацией.

Со стороны клиента

Со стороны клиента можно:

  1. Вручную установить корневой сертификат ISRG Root X1, если он остутствует в хранилище используемой системы или ПО.
  2. Удалить устаревший корневой сертификата DST Root CA X3. Наличие устаревшего корневого сертификата может мешать нормальной работе с сервисами, использующими сертификаты Let’s Encrypt.

Внимание! Решить проблему данным способом можно не на всех устройствах.

Windows 7

В операционной системе Windows 7 цепочка корневых сертификатов должна была обновиться, если включены обновления операционной системы, в ином случае корневой сертификат необходимо установить самостоятельно, выполнив следующие действия:

  1. Скачайте корневой сертификат ISRG Root X1 с сайта Let’s Encrypt в формате der.
  2. Запустите скачанный файл и разрешите его открытие, нажав «Открыть».
  3. В появившемся окне нажмите «Install Cerificate»:
  4. Выберите, для кого необходимо установить сертификат, и нажмите «Далее».
  5. Выберите пункт «Place all certificates in the following store» и нажмите «Browse»:
  6. Выберите хранилище «Trusted Root Certification Authorities» и нажмите «OK»:
  7. Нажмите «Next», проверьте корректность выбранных данных и нажмите «Finish».
  8. Перегрузите ПК и проверьте работу сервисов, с которыми возникали проблемы доступа.
OpenSSL 1.0.x

Если в системе используется устаревшая версия OpenSSL, то необходимо удалить из доверенных корневых сертификатов устаревший следующим образом:

  • Для Debian/Ubuntu отредактируйте файл /etc/ca-certificates.conf установив символ ! в начале строки mozilla/DST_Root_CA_X3.crt и выполните команду:
update-ca-certificates
CentOS
1. Для проверки наличия корневого сертификата в списке доверенных, выполните в терминале команду:
# awk -v cmd='openssl x509 -noout -subject' ' /BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-bundle.crt | grep "ISRG Root X1"

Если в выводе команды будет фигурировать subject=C = US, O = Internet Security Research Group, CN = ISRG Root X1, то нет необходимости выполнять какие-либо действия, а если нет, то перейдите к следующему шагу.

2. Выполните в терминале следующие команды:
# trust dump --filter "pkcs11:id=%c4%a7%b1%a4%7b%2c%71%fa%db%e1%4b%90%75%ff%c4%15%60%85%89%10" | openssl x509 | sudo tee /etc/pki/ca-trust/source/blacklist/DST-Root-CA-X3.pem
sudo update-ca-trust
Debian/Ubuntu
1. Для проверки наличия корневого сертификата в списке доверенных, выполните в терминале команду:
# awk -v cmd='openssl x509 -noout -subject' ' /BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-certificates.crt | grep "ISRG Root X1"

Если в выводе команды будет фигурировать subject=C = US, O = Internet Security Research Group, CN = ISRG Root X1, то нет необходимости выполнять какие-либо действия, а если нет, то перейдите к следующему шагу.

2. Выполните в терминале команду:
# curl -k https://letsencrypt.org/certs/isrgrootx1.pem.txt | sudo tee /usr/share/ca-certificates/mozilla/ISRG_Root_X1.crt ; sudo echo "mozilla/ISRG_Root_X1.crt" >> /etc/ca-certificates.conf ; sudo update-ca-certificates
image_pdfimage_print

WordPress Взаимодействие с поисковыми системами после перезда сайта

Тонкости настройки 301 редиректа на старом домене

Когда техническая часть переноса завершена, остается только настроить правильное взаимодействие с поисковыми системами, чтобы они поняли о «переезде». Кроме того, важно сохранить позиции в выдаче, из которой посетители будут попадать уже на новый домен. В этом и заключается миссия 301 редиректа.

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

Options +FollowSymLinks
RewriteEngine on
RewriteRule (.*) http://site2.ru/$1 [R=301,L]

Примечание: на месте site2.ru указываете ваш новый домен. Вот и все, процедура успешно завершена.

Как сохранить PR и тИЦ при переносе сайта на новый домен?

Конечно, никому не хочется терять показатели тИЦ и PR при переезде, особенно если их значения зарабатывались долгое время.

Что касается Page Rank от Google, то изменения в .htaccess, описанные выше, позволяют также сохранить заветное число на новом доменном имени. Больше делать ничего не нужно.

А вот с Яндексом все чуточку сложнее. Вам нужно сделать так, чтобы редирект 301 срабатывал всегда, но только не в случаях обращения к robots.txt. Для этого достаточно добавить в .htaccess следующий код:

<FilesMatch "robots.txt$">
RewriteEngine off
</FilesMatch>
Options +FollowSymLinks
RewriteEngine on
RewriteRule (.*) http://site2.ru/$1 [R=301,L]

Кроме того, в robots.txt нужно добавить следующее:

User-Agent: *
Disallow:
Host: site2.ru

И не забывайте, что site2.ru ОБЯЗАТЕЛЬНО нужно заменить на ваш новый домен.

https://shneider-host.ru/blog/kak-pravilno-perenesti-wordpress-sayt-na-novyy-domen.html

image_pdfimage_print

WordPress плагин Polylang для создания мультиязычного сайта

Задача сделать сайт на двух языках. Есть несколько способов, самый простой завести несколько корней, в зависимости от количества языков. Тогда они будут находиться по таким адресам, например:

www.site.com/ru и www.site.com/en

Но мне нужно, что бы страницы показывали перевод прозрачно с помощью выбора языка, т.е. находясь на какой то странице и нажав другой язык я получал бы эту же страницу в переводе. Решил это сделать с помощью плагина Polylang.

Устанавливаем плагин с Админ панели WordPress.

Заполняем вкладки.

Теперь когда создаем Записи или Страницы появится новая опция выбора языка

А через меню Страницы можно редактировать или добавлять/удалять связанные переводом страницы

Также нужно создать два (в моем случае) меню, для основного языка и переводного

image_pdfimage_print

WordPress перенос сайта в другое место или на другой домен

Мне понадобилось скопировать сайт в другую директорию (но принцип переноса на другой домен тот же).

1. Создаем новый каталог:
# mkdir /home/www/newimp
# chown -R nginx:www-data /home/www/newimp
2. Делаем копию сайта:
# cp /home/www/imp /home/www/newimp
3. Переименуем файл настроек:
# cd /home/www/newimp/ && mv wp-config.php wp-config.php_
4. Делаем или дамп БД или копию БД из phpmyadmin (мне нужно второе).

В окошке SQL пишем три команды (меняем старое название сайта на новое):

UPDATE wp_options SET option_value = replace(option_value, 'https://tst-amo.net.ua/imp', 'https://tst-amo.net.ua/newimp') WHERE option_name = 'home' OR option_name = 'siteurl';
UPDATE wp_posts SET guid = replace(guid, 'https://tst-amo.net.ua/imp','https://tst-amo.net.ua/newimp');
UPDATE wp_posts SET post_content = replace(post_content, 'https://tst-amo.net.ua/imp', 'https://tst-amo.net.ua/newimp');
5. Создаем виртуальный хост nginx для нового сайта:
# cp /etc/nginx/sites-available/imp /etc/nginx/sites-available/newimp

Меняем в нем путь imp на newimp. Подключаем и запускаем:

# ln -s /etc/nginx/sites-available/newimp /etc/nginx/sites-enabled/newimp
# nginx -t
# nginx -s reload

То же делаем и с пулом (если нужно) php-fpm.

# systemctl reload php-fpm
6. Заходим через браузер на наш новый сайт и вбиваем новые настройки (логин, пароль и т.д. нужно взять со старого wp-config.php_).
image_pdfimage_print

swapon: read swap header failed: invalid argument

Понадобилось срочно увеличить файл подкачки на сервере. Но при попытке включения получил ошибку

# swapon /home/swap.swap
swapon: /home/swap.swap: swapon failed: Недопустимый аргумент

Алгоритм создания был такой:

# touch /home/swap.swap
# fallocate -l 4G /home/swap.swap
# chmod 600 /home/swap.swap
# mkswap /home/swap.swap
Setting up swapspace version 1, size = 4194300 KiB
без метки, UUID=f426e847-8fc3-4d3f-9ca8-b3d62a1d81c7
# swapon /home/swap.swap
swapon: /home/swap.swap: swapon failed: Недопустимый аргумент

Решил проблему с помощью dd:

# touch /home/swap.swap
# dd if=/dev/zero of=/home/swap.swap count=4096 bs=1MiB
# chmod 600 /home/swap.swap
# mkswap /home/swap.swap
# swapon /home/swap.swap

И прописал в fstab:

# vi /etc/fstab

эту строку:

/home/swap.swap   swap    swap    sw  0   0

Проверить размер можно:

# swapon --summary
Filename         Type       Size    Used    Priority
/dev/dm-1        partition  2097148 1610552 -2
/home/swap.swap  file       4194300  0      -3

# free -h
       total    used    free   shared   buff/cache   available
Mem:   3,7G     2,2G    117M   6,1M     1,4G         1,3G
Swap:  6,0G     1,5G    4,5G

Смотрим

# cat /proc/sys/vm/swappiness
60

Уменьшим это значение выполнив команду:

# sysctl vm.swappiness=10

И пропишем ее, что бы сохранилась после перезагрузки:

# vi /etc/sysctl.conf

добавить эту строку

vm.swappiness = 10
vm.vfs_cache_pressure = 50
image_pdfimage_print

WorPress установка

Прежде чем начать установку подготовим www-сервер (у меня это nginx + php-fpm):

$ vi /etc/nginx/sites-available/imp
server {
listen 80;
## Your website name goes here.
server_name imp.tst-amo.net.ua;
## Your only path reference.
#root /home/www/imp;
## This should be in your http block and if it is, it's not needed here.
#index index.php;
return 301 https://tst-amo.net.ua$request_uri;
}

server {
# listens both on IPv4 and IPv6 on 443 and enables HTTPS and HTTP/2 support.
# HTTP/2 is available in nginx 1.9.5 and above.
listen *:443 ssl http2;
#listen [::]:443 ssl http2;
server_name imp.tst-amo.net.ua www.imp.tst-amo.net.ua;
## Your only path reference.
root /home/www/imp;

# Let'sCript
include acme.conf;
include /etc/nginx/conf.d/hsts.conf;
include /etc/nginx/conf.d/ssl.conf;

location = / {
#Учим WordPress работе с красивыми ссылками
index index.php index.html;
try_files $uri $uri/ /index.php?$args;
}

# Не сообщать об отсутствии favicon.ico
location = /favicon.ico {
log_not_found off;
access_log off;
}

# Не сообщать об отсутствии robots.txt
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}

# Запретить доступ к файлам, начинающимся с точки. Например .htaccess
location ~ /\. {
deny all;
}
# Запретить доступ к файлам php в директориях uploads, files.
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}

rewrite /wp-admin$ $scheme://$host$uri/ permanent;

# Для файлов отключить логирование, установить максимальный срок жизни кэша.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off; log_not_found off; expires 90d;
}

set $cache_uri $request_uri;

# Запретить кэширование, если используются POST запросы.
if ($request_method = POST) {
set $cache_uri 'null cache';
}

if ($query_string != "") {
set $cache_uri 'null cache';
}

# Запретить кэширование при доступе к служебным скриптам.
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.p
hp|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
set $cache_uri 'null cache';
}

# Запретить кэширование, если используются cookie.
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
set $cache_uri 'null cache';
}

# Отдавать кэш.
location / {
try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php?$args ;
}

# Для файлов php отдавать обработку FASTCGI серверу.
location ~ [^/]\.php(/|$) {
root /home/www/imp;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}

fastcgi_index index.php;
include fastcgi_params;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
$ sudo ln -s /etc/nginx/sites-available/imp /etc/nginx/sites-enabled/

$ sudo nginx -t
$ sudo nginx -s reload

$ sudo vi /etc/php-fpm.d/imp.tst-amo.net.ua.conf
[imp.tst-amo.net.ua]
listen = /var/run/php-fpm/imp.tst-amo.net.ua.sock
listen.mode = 0666
user = nginx
group = www-data
chdir = /home/www/imp

; В зависимости от нагрузки меняем параметры
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 500

request_slowlog_timeout = 3s
slowlog = /var/log/php-fpm/php-slow_www.log

; Default Value: clean env
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
$ sudo service php-fpm reload

Создаем каталог для нашего сайта:

$ sudo mkdir /home/www/imp 
$ sudo chown -R nginx:www-data /home/www/imp/
$ sudo chmod -R 755 /home/www/imp/
$ cd /home/www/imp

Загружаем последнюю версию системы управления контентом из официального сайта:

$ wget -c http://wordpress.org/latest.tar.gz

Распаковываем содержимое архива в текущую папку:

$ tar -xzvf latest.tar.gz

Копируем файлы WordPress из текущей директории wordpress в каталог /home/www/imp/:

$ rsync -av wordpress/* /home/www/imp/

Создаем БД для сайта:

$sudo mysql -u root -p

Введите пароль суперпользователя, а затем по очереди выполняйте такие команды для создания базы данных, пользователя и установки для них правильных привилегий:

mysql> CREATE DATABASE imp;
mysql> CREATE USER 'imp'@'localhost' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON imp.* TO 'imp'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> EXIT;

Заходим на наш сайт и начинаем установку:

https://tst-amo.net.ua/imp

Добавим возможность работы по FTP (за это у меня отвечает ProFTPd)

# adduser imp -s /sbin/nologin -d /home/www/imp
# usermod -aG www-data imp
# ftpasswd --passwd --name=imp --change-password
# proftpd -t
# service proftpd reload
# ln -s /home/www/imp /home/

Проверяем.

image_pdfimage_print

MySQL 45 [Note] Aborted connection 45 to db: ‘postfix’ user: ‘postfix’ host: ‘localhost’ (Got an error reading communication packets)

Замечание возникло после обновления версии 5.6 на 5.7.

Согласно документации это может быть вызвано следующими причинами:

If a client successfully connects but later disconnects improperly or is terminated, the server increments the Aborted_clients status variable, and logs an Aborted connection message to the error log. The cause can be any of the following:

Other reasons for problems with aborted connections or aborted clients:

  • The max_allowed_packet variable value is too small or queries require more memory than you have allocated for mysqld. See Section B.3.2.8, “Packet Too Large”.
  • Use of Ethernet protocol with Linux, both half and full duplex. Some Linux Ethernet drivers have this bug. You should test for this bug by transferring a huge file using FTP between the client and server machines. If a transfer goes in burst-pause-burst-pause mode, you are experiencing a Linux duplex syndrome. Switch the duplex mode for both your network card and hub/switch to either full duplex or to half duplex and test the results to determine the best setting.
  • A problem with the thread library that causes interrupts on reads.
  • Badly configured TCP/IP.
  • Faulty Ethernets, hubs, switches, cables, and so forth. This can be diagnosed properly only by replacing hardware.

Так как сеть и ее настройки не менялись, а только обновились Dovecot, Postfix и MySQL то виновником была какая то из этих программ.

В итоге, изменил и добавил такие переменные:

# ee /usr/local/etc/mysql/my.cnf

[mysqld]
....
max_allowed_packet = 256M # было 16М
max_connections = 400
wait_timeout = 28800
connect_timeout = 10
interactive_timeout = 28800
....

перестартуем сервис:

# service mysql-server restart
# service mysql-server status

Полностью проблему не убрало, но стало вместо 1 раза в 2-3 минуты, до 1 раза в 25-35 минут.

https://dovecot.org/pipermail/dovecot/2019-October/117403.html

https://deniapps.com/blog/mysql-rds-aborted-connection-error-aws-lambda

image_pdfimage_print

MySQL [Warning] InnoDB: Table mysql/innodb_table_stats has length mismatch in the column name table_name. Please run mysql_upgrade

После обновления MySQL 5.6 на MySQL 5.7 в логах вылезла ошибка:

[Warning] InnoDB: Table mysql/innodb_table_stats has length mismatch in the column name table_name. Please run mysql_upgrade

Запускаем mysql_upgrade, предварительно сделав резервную копию!!!

# mysql_upgrade -p
  • mysql_upgrade должен выполняться каждый раз, когда вы обновляете MySQL
  • mysql_upgrade проверяет все таблицы во всех базах данных на предмет несовместимости с текущей версией сервера.
  • mysql_upgrade также обновляет системные таблицы, чтобы вы могли использовать новые привилегии или возможности, которые могли быть добавлены.

Чтобы проверить и восстановить таблицы или обновить системные таблицы, выполняем команды:

# mysqlcheck --all-databases --check-upgrade --auto-repair
# mysql < fix_priv_tables
# mysqlcheck --all-databases --check-upgrade --fix-db-names --fix-tables-names

Чтобы выполнить только обновление таблиц:

# mysql_upgrade
image_pdfimage_print

WordPress PDF & Print by BestWebSoft

БЕСПЛАТНЫЕ ФУНКЦИИ

  • Автоматически добавляйте кнопки PDF & Print на:
    • Страницы
    • Записи
    • Результаты поиска
    • Архивы
    • Пользовательские типы записей
  • Выбирайте расположение кнопок в контенте:
    • Вверху слева
    • Вверху справа
    • Внизу слева
    • Внизу справа
    • Вверху и внизу справа
    • Вверху и внизу слева
  • Добавляйте кнопки в область виджетов
  • Добавляйте кнопки с помощью шорткода
  • Устанавливайте тип кнопки:
    • Изображение
    • Текст
    • Изображение + текст
  • Изменяйте действие кнопки PDF:
    • Загрузить PDF-документ
    • Открыть PDF-документ в новом окне
  • Отображайте кнопки PDF & Print для определенных ролей пользователей
  • Отображайте данные сгенерированные шорткодом в документе
  • Добавляйте заголовки и избранные изображения в документ
  • Задавайте пользовательский размер избраного изображения
  • Устанавливайте размер PDF-документа
  • Задавайте пользовательские поля для PDF-документа:
    • Слева
    • Справа
    • Сверху
    • Снизу
  • Настраивайте стили документа
  • Создать PDF, который полностью копирует страницу
  • Добавление пользовательского кода через страницу настроек плагина
  • Совместимость с последней версией WordPress
  • Невероятно простые настройки для быстрой установки без изменения кода
  • Подробная пошаговая документация и видео
  • Поддержка RTL языков
image_pdfimage_print

Python3

Встроенные объекты

Object type        Example literals/creation
Numbers            1234, 3.1415, 3+4j, 0b111, Decimal(), Fraction()
Strings            'spam', "Bob's", b'a\x01c', u'sp\xc4m'
Lists              [1, [2, 'three'], 4.5], list(range(10))
Dictionaries       {'food': 'spam', 'taste': 'yum'}, dict(hours=10)
Tuples             (1, 'spam', 4, 'U'), tuple('spam'), namedtuple
Files              open('eggs.txt'), open(r'C:\ham.bin', 'wb')
Sets               set('abc'), {'a', 'b', 'c'}
Other core types   Booleans, types, None

Numbers

>>> 123 + 222 # Integer addition
345
>>> 1.5 * 4 # Floating-point multiplication
6.0
>>> 2 ** 100 # 2 to the power 100, again
1267650600228229401496703205376
>>> len(str(2 ** 1000000)) # How many digits in a really BIG number?
301030
start experimenting with floating-point
numbers, you’re likely to stumble across something that may look a bit odd at first
glance:
>>> 3.1415 * 2 # repr: as code (Pythons < 2.7 and 3.1)
6.2830000000000004
>>> print(3.1415 * 2) # str: user-friendly
6.283
>>> import math
>>> math.pi
3.141592653589793
>>> math.sqrt(85)
9.219544457292887
>>> import random
>>> random.random()
0.7082048489415967
>>> random.choice([1, 2, 3, 4])
1

String

>>> S = 'Spam' # Make a 4-character string, and assign it to a name
>>> len(S) # Length
4
>>> S[0] # The first item in S, indexing by zero-based position
'S'
>>> S[1] # The second item from the left
'p'

In Python, we can also index backward, from the end—positive indexes count from
the left, and negative indexes count back from the right:

>>> S[-1] # The last item from the end in S
'm'
>>> S[-2] # The second-to-last item from the end
'a'

Formally, a negative index is simply added to the string’s length, so the following two
operations are equivalent (though the first is easier to code and less easy to get wrong):

>>> S[-1] # The last item in S
'm'
>>> S[len(S)-1] # Negative indexing, the hard way
'm'

In addition to simple positional indexing, sequences also support a more general form
of indexing known as slicing, which is a way to extract an entire section (slice) in a single
step. For example:

>>> S # A 4-character string
'Spam'
>>> S[1:3] # Slice of S from offsets 1 through 2 (not 3)
'pa'
>>> S[1:] # Everything past the first (1:len(S))
'pam'
>>> S # S itself hasn't changed
'Spam'
>>> S[0:3] # Everything but the last
'Spa'
>>> S[:3] # Same as S[0:3]
'Spa'
>>> S[:-1] # Everything but the last again, but simpler (0:-1)
'Spa'
>>> S[:] # All of S as a top-level copy (0:len(S))
'Spam'
>>> S + 'xyz' # Concatenation
'Spamxyz'
>>> S # S is unchanged
'Spam'
>>> S * 8 # Repetition
'SpamSpamSpamSpamSpamSpamSpamSpam'

Immutability

Also notice in the prior examples that we were not changing the original string with
any of the operations we ran on it. Every string operation is defined to produce a new
string as its result, because strings are immutable in Python—they cannot be changed
in place after they are created. In other words, you can never overwrite the values of
immutable objects. For example, you can’t change a string by assigning to one of its
positions, but you can always build a new one and assign it to the same name. Because
Python cleans up old objects as you go (as you’ll see later), this isn’t as inefficient as it
may sound:

>>> S
'Spam'
>>> S[0] = 'z' # Immutable objects cannot be changed
...error text omitted...
TypeError: 'str' object does not support item assignment
>>> S = 'z' + S[1:] # But we can run expressions to make new objects
>>> S
'zpam'

Every object in Python is classified as either immutable (unchangeable) or not. In terms
of the core types, numbers, strings, and tuples are immutable; lists, dictionaries, and
sets are not—they can be changed in place freely, as can most new objects you’ll code
with classes.

Strictly speaking, you can change text-based data in place if you either expand it into a
list of individual characters and join it back together with nothing between, or use the
newer bytearray type available in Pythons 2.6, 3.0, and later:

>>> S = 'shrubbery'
>>> L = list(S) # Expand to a list: [...]
>>> L
['s', 'h', 'r', 'u', 'b', 'b', 'e', 'r', 'y']
>>> L[1] = 'c' # Change it in place
>>> ''.join(L) # Join with empty delimiter
'scrubbery'
>>> B = bytearray(b'spam') # A bytes/list hybrid (ahead)
>>> B.extend(b'eggs') # 'b' needed in 3.X, not 2.X
>>> B # B[i] = ord(c) works here too
bytearray(b'spameggs')
>>> B.decode() # Translate to normal string
'spameggs'

Type-Specific Methods

For example, the string find method is the basic substring search operation (it returns
the offset of the passed-in substring, or −1 if it is not present), and the string replace
method performs global searches and replacements; both act on the subject that they
are attached to and called from:

>>> S = 'Spam'
>>> S.find('pa') # Find the offset of a substring in S
1
>>> S
'Spam'
>>> S.replace('pa', 'XYZ') # Replace occurrences of a string in S with another
'SXYZm'
>>> S
'Spam'
>> line = 'aaa,bbb,ccccc,dd'
>>> line.split(',') # Split on a delimiter into a list of substrings
['aaa', 'bbb', 'ccccc', 'dd']
>>> S = 'spam'
>>> S.upper() # Upper- and lowercase conversions
'SPAM'
>>> S.isalpha() # Content tests: isalpha, isdigit, etc.
True
>>> line = 'aaa,bbb,ccccc,dd\n'
>>> line.rstrip() # Remove whitespace characters on the right side
'aaa,bbb,ccccc,dd'
>>> line.rstrip().split(',') # Combine two operations
['aaa', 'bbb', 'ccccc', 'dd']

Notice the last command here—it strips before it splits because Python runs from left
to right, making a temporary result along the way. Strings also support an advanced
substitution operation known as formatting, available as both an expression (the original)
and a string method call (new as of 2.6 and 3.0); the second of these allows you
to omit relative argument value numbers as of 2.7 and 3.1:

>> '%s, eggs, and %s' % ('spam', 'SPAM!') # Formatting expression (all)
'spam, eggs, and SPAM!'
>>> '{0}, eggs, and {1}'.format('spam', 'SPAM!') # Formatting method (2.6+, 3.0+)
'spam, eggs, and SPAM!'
>>> '{}, eggs, and {}'.format('spam', 'SPAM!') # Numbers optional (2.7+, 3.1+)
'spam, eggs, and SPAM!'

Formatting is rich with features, which we’ll postpone discussing until later in this
book, and which tend to matter most when you must generate numeric reports:

>>> '{:,.2f}'.format(296999.2567) # Separators, decimal digits
'296,999.26'
>>> '%.2f | %+05d' % (3.14159, −42) # Digits, padding, signs
'3.14 | −0042'
image_pdfimage_print